SQLStore: Ensure that sessions are always closed (#55864)
* SQLStore: Ensure that sessions are always closed Delete `NewSession()` in favour of `WithDbSession()` * Add WithDbSessionForceNewSession to the interface * Apply suggestions from code review
This commit is contained in:
@@ -17,10 +17,15 @@ import (
|
|||||||
|
|
||||||
func TestPasswordMigrationCommand(t *testing.T) {
|
func TestPasswordMigrationCommand(t *testing.T) {
|
||||||
// setup datasources with password, basic_auth and none
|
// setup datasources with password, basic_auth and none
|
||||||
sqlstore := sqlstore.InitTestDB(t)
|
store := sqlstore.InitTestDB(t)
|
||||||
session := sqlstore.NewSession(context.Background())
|
err := store.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error {
|
||||||
defer session.Close()
|
passwordMigration(t, sess, store)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func passwordMigration(t *testing.T, session *sqlstore.DBSession, sqlstore *sqlstore.SQLStore) {
|
||||||
ds := []*datasources.DataSource{
|
ds := []*datasources.DataSource{
|
||||||
{Type: "influxdb", Name: "influxdb", Password: "foobar", Uid: "influx"},
|
{Type: "influxdb", Name: "influxdb", Password: "foobar", Uid: "influx"},
|
||||||
{Type: "graphite", Name: "graphite", BasicAuthPassword: "foobar", Uid: "graphite"},
|
{Type: "graphite", Name: "graphite", BasicAuthPassword: "foobar", Uid: "graphite"},
|
||||||
|
|||||||
@@ -54,36 +54,38 @@ func (dc *databaseCache) internalRunGC() {
|
|||||||
|
|
||||||
func (dc *databaseCache) Get(ctx context.Context, key string) (interface{}, error) {
|
func (dc *databaseCache) Get(ctx context.Context, key string) (interface{}, error) {
|
||||||
cacheHit := CacheData{}
|
cacheHit := CacheData{}
|
||||||
session := dc.SQLStore.NewSession(ctx)
|
|
||||||
defer session.Close()
|
|
||||||
|
|
||||||
exist, err := session.Where("cache_key= ?", key).Get(&cacheHit)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !exist {
|
|
||||||
return nil, ErrCacheItemNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
if cacheHit.Expires > 0 {
|
|
||||||
existedButExpired := getTime().Unix()-cacheHit.CreatedAt >= cacheHit.Expires
|
|
||||||
if existedButExpired {
|
|
||||||
err = dc.Delete(ctx, key) // ignore this error since we will return `ErrCacheItemNotFound` anyway
|
|
||||||
if err != nil {
|
|
||||||
dc.log.Debug("Deletion of expired key failed: %v", err)
|
|
||||||
}
|
|
||||||
return nil, ErrCacheItemNotFound
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
item := &cachedItem{}
|
item := &cachedItem{}
|
||||||
if err = decodeGob(cacheHit.Data, item); err != nil {
|
err := dc.SQLStore.WithDbSession(ctx, func(session *sqlstore.DBSession) error {
|
||||||
return nil, err
|
exist, err := session.Where("cache_key= ?", key).Get(&cacheHit)
|
||||||
}
|
|
||||||
|
|
||||||
return item.Val, nil
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !exist {
|
||||||
|
return ErrCacheItemNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if cacheHit.Expires > 0 {
|
||||||
|
existedButExpired := getTime().Unix()-cacheHit.CreatedAt >= cacheHit.Expires
|
||||||
|
if existedButExpired {
|
||||||
|
err = dc.Delete(ctx, key) // ignore this error since we will return `ErrCacheItemNotFound` anyway
|
||||||
|
if err != nil {
|
||||||
|
dc.log.Debug("Deletion of expired key failed: %v", err)
|
||||||
|
}
|
||||||
|
return ErrCacheItemNotFound
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = decodeGob(cacheHit.Data, item); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return item.Val, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dc *databaseCache) Set(ctx context.Context, key string, value interface{}, expire time.Duration) error {
|
func (dc *databaseCache) Set(ctx context.Context, key string, value interface{}, expire time.Duration) error {
|
||||||
@@ -93,34 +95,33 @@ func (dc *databaseCache) Set(ctx context.Context, key string, value interface{},
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
session := dc.SQLStore.NewSession(context.Background())
|
return dc.SQLStore.WithDbSession(ctx, func(session *sqlstore.DBSession) error {
|
||||||
defer session.Close()
|
var expiresInSeconds int64
|
||||||
|
if expire != 0 {
|
||||||
|
expiresInSeconds = int64(expire) / int64(time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
var expiresInSeconds int64
|
// attempt to insert the key
|
||||||
if expire != 0 {
|
sql := `INSERT INTO cache_data (cache_key,data,created_at,expires) VALUES(?,?,?,?)`
|
||||||
expiresInSeconds = int64(expire) / int64(time.Second)
|
_, err := session.Exec(sql, key, data, getTime().Unix(), expiresInSeconds)
|
||||||
}
|
if err != nil {
|
||||||
|
// attempt to update if a unique constrain violation or a deadlock (for MySQL) occurs
|
||||||
// attempt to insert the key
|
// if the update fails propagate the error
|
||||||
sql := `INSERT INTO cache_data (cache_key,data,created_at,expires) VALUES(?,?,?,?)`
|
// which eventually will result in a key that is not finally set
|
||||||
_, err = session.Exec(sql, key, data, getTime().Unix(), expiresInSeconds)
|
// but since it's a cache does not harm a lot
|
||||||
if err != nil {
|
if dc.SQLStore.Dialect.IsUniqueConstraintViolation(err) || dc.SQLStore.Dialect.IsDeadlock(err) {
|
||||||
// attempt to update if a unique constrain violation or a deadlock (for MySQL) occurs
|
sql := `UPDATE cache_data SET data=?, created_at=?, expires=? WHERE cache_key=?`
|
||||||
// if the update fails propagate the error
|
_, err = session.Exec(sql, data, getTime().Unix(), expiresInSeconds, key)
|
||||||
// which eventually will result in a key that is not finally set
|
if err != nil && dc.SQLStore.Dialect.IsDeadlock(err) {
|
||||||
// but since it's a cache does not harm a lot
|
// most probably somebody else is upserting the key
|
||||||
if dc.SQLStore.Dialect.IsUniqueConstraintViolation(err) || dc.SQLStore.Dialect.IsDeadlock(err) {
|
// so it is safe enough not to propagate this error
|
||||||
sql := `UPDATE cache_data SET data=?, created_at=?, expires=? WHERE cache_key=?`
|
return nil
|
||||||
_, err = session.Exec(sql, data, getTime().Unix(), expiresInSeconds, key)
|
}
|
||||||
if err != nil && dc.SQLStore.Dialect.IsDeadlock(err) {
|
|
||||||
// most probably somebody else is upserting the key
|
|
||||||
// so it is safe enough not to propagate this error
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
return err
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dc *databaseCache) Delete(ctx context.Context, key string) error {
|
func (dc *databaseCache) Delete(ctx context.Context, key string) error {
|
||||||
|
|||||||
@@ -43,10 +43,10 @@ func benchmarkFilter(b *testing.B, numDs, numPermissions int) {
|
|||||||
require.NoError(b, err)
|
require.NoError(b, err)
|
||||||
|
|
||||||
var datasources []datasources.DataSource
|
var datasources []datasources.DataSource
|
||||||
sess := store.NewSession(context.Background())
|
err = store.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error {
|
||||||
err = sess.SQL(baseSql+acFilter.Where, acFilter.Args...).Find(&datasources)
|
return sess.SQL(baseSql+acFilter.Where, acFilter.Args...).Find(&datasources)
|
||||||
|
})
|
||||||
require.NoError(b, err)
|
require.NoError(b, err)
|
||||||
sess.Close()
|
|
||||||
require.Len(b, datasources, numPermissions)
|
require.Len(b, datasources, numPermissions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -168,40 +168,41 @@ func TestFilter_Datasources(t *testing.T) {
|
|||||||
t.Run(tt.desc, func(t *testing.T) {
|
t.Run(tt.desc, func(t *testing.T) {
|
||||||
store := sqlstore.InitTestDB(t)
|
store := sqlstore.InitTestDB(t)
|
||||||
|
|
||||||
sess := store.NewSession(context.Background())
|
err := store.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error {
|
||||||
defer sess.Close()
|
// seed 10 data sources
|
||||||
|
for i := 1; i <= 10; i++ {
|
||||||
// seed 10 data sources
|
dsStore := dsService.CreateStore(store, log.New("accesscontrol.test"))
|
||||||
for i := 1; i <= 10; i++ {
|
err := dsStore.AddDataSource(context.Background(), &datasources.AddDataSourceCommand{Name: fmt.Sprintf("ds:%d", i), Uid: fmt.Sprintf("uid%d", i)})
|
||||||
dsStore := dsService.CreateStore(store, log.New("accesscontrol.test"))
|
require.NoError(t, err)
|
||||||
err := dsStore.AddDataSource(context.Background(), &datasources.AddDataSourceCommand{Name: fmt.Sprintf("ds:%d", i), Uid: fmt.Sprintf("uid%d", i)})
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
baseSql := `SELECT data_source.* FROM data_source WHERE`
|
|
||||||
acFilter, err := accesscontrol.Filter(
|
|
||||||
&user.SignedInUser{
|
|
||||||
OrgID: 1,
|
|
||||||
Permissions: map[int64]map[string][]string{1: tt.permissions},
|
|
||||||
},
|
|
||||||
tt.sqlID,
|
|
||||||
tt.prefix,
|
|
||||||
tt.actions...,
|
|
||||||
)
|
|
||||||
|
|
||||||
if !tt.expectErr {
|
|
||||||
require.NoError(t, err)
|
|
||||||
var datasources []datasources.DataSource
|
|
||||||
err = sess.SQL(baseSql+acFilter.Where, acFilter.Args...).Find(&datasources)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
assert.Len(t, datasources, len(tt.expectedDataSources))
|
|
||||||
for i, ds := range datasources {
|
|
||||||
assert.Equal(t, tt.expectedDataSources[i], ds.Name)
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
require.Error(t, err)
|
baseSql := `SELECT data_source.* FROM data_source WHERE`
|
||||||
}
|
acFilter, err := accesscontrol.Filter(
|
||||||
|
&user.SignedInUser{
|
||||||
|
OrgID: 1,
|
||||||
|
Permissions: map[int64]map[string][]string{1: tt.permissions},
|
||||||
|
},
|
||||||
|
tt.sqlID,
|
||||||
|
tt.prefix,
|
||||||
|
tt.actions...,
|
||||||
|
)
|
||||||
|
|
||||||
|
if !tt.expectErr {
|
||||||
|
require.NoError(t, err)
|
||||||
|
var datasources []datasources.DataSource
|
||||||
|
err = sess.SQL(baseSql+acFilter.Where, acFilter.Args...).Find(&datasources)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Len(t, datasources, len(tt.expectedDataSources))
|
||||||
|
for i, ds := range datasources {
|
||||||
|
assert.Equal(t, tt.expectedDataSources[i], ds.Name)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
require.Error(t, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,9 @@ func (ss *sqlStore) DeleteAlertNotification(ctx context.Context, cmd *models.Del
|
|||||||
|
|
||||||
func (ss *sqlStore) DeleteAlertNotificationWithUid(ctx context.Context, cmd *models.DeleteAlertNotificationWithUidCommand) error {
|
func (ss *sqlStore) DeleteAlertNotificationWithUid(ctx context.Context, cmd *models.DeleteAlertNotificationWithUidCommand) error {
|
||||||
existingNotification := &models.GetAlertNotificationsWithUidQuery{OrgId: cmd.OrgId, Uid: cmd.Uid}
|
existingNotification := &models.GetAlertNotificationsWithUidQuery{OrgId: cmd.OrgId, Uid: cmd.Uid}
|
||||||
if err := getAlertNotificationWithUidInternal(ctx, existingNotification, ss.db.NewSession(ctx)); err != nil {
|
if err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||||
|
return getAlertNotificationWithUidInternal(ctx, existingNotification, sess)
|
||||||
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +81,9 @@ func (ss *sqlStore) DeleteAlertNotificationWithUid(ctx context.Context, cmd *mod
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ss *sqlStore) GetAlertNotifications(ctx context.Context, query *models.GetAlertNotificationsQuery) error {
|
func (ss *sqlStore) GetAlertNotifications(ctx context.Context, query *models.GetAlertNotificationsQuery) error {
|
||||||
return getAlertNotificationInternal(ctx, query, ss.db.NewSession(ctx))
|
return ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||||
|
return getAlertNotificationInternal(ctx, query, sess)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *sqlStore) GetAlertNotificationUidWithId(ctx context.Context, query *models.GetAlertNotificationUidQuery) error {
|
func (ss *sqlStore) GetAlertNotificationUidWithId(ctx context.Context, query *models.GetAlertNotificationUidQuery) error {
|
||||||
@@ -90,8 +94,9 @@ func (ss *sqlStore) GetAlertNotificationUidWithId(ctx context.Context, query *mo
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err := getAlertNotificationUidInternal(ctx, query, ss.db.NewSession(ctx))
|
if err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||||
if err != nil {
|
return getAlertNotificationUidInternal(ctx, query, sess)
|
||||||
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +110,9 @@ func newAlertNotificationUidCacheKey(orgID, notificationId int64) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ss *sqlStore) GetAlertNotificationsWithUid(ctx context.Context, query *models.GetAlertNotificationsWithUidQuery) error {
|
func (ss *sqlStore) GetAlertNotificationsWithUid(ctx context.Context, query *models.GetAlertNotificationsWithUidQuery) error {
|
||||||
return getAlertNotificationWithUidInternal(ctx, query, ss.db.NewSession(ctx))
|
return ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||||
|
return getAlertNotificationWithUidInternal(ctx, query, sess)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *sqlStore) GetAllAlertNotifications(ctx context.Context, query *models.GetAllAlertNotificationsQuery) error {
|
func (ss *sqlStore) GetAllAlertNotifications(ctx context.Context, query *models.GetAllAlertNotificationsQuery) error {
|
||||||
@@ -444,7 +451,9 @@ func (ss *sqlStore) UpdateAlertNotification(ctx context.Context, cmd *models.Upd
|
|||||||
func (ss *sqlStore) UpdateAlertNotificationWithUid(ctx context.Context, cmd *models.UpdateAlertNotificationWithUidCommand) error {
|
func (ss *sqlStore) UpdateAlertNotificationWithUid(ctx context.Context, cmd *models.UpdateAlertNotificationWithUidCommand) error {
|
||||||
getAlertNotificationWithUidQuery := &models.GetAlertNotificationsWithUidQuery{OrgId: cmd.OrgId, Uid: cmd.Uid}
|
getAlertNotificationWithUidQuery := &models.GetAlertNotificationsWithUidQuery{OrgId: cmd.OrgId, Uid: cmd.Uid}
|
||||||
|
|
||||||
if err := getAlertNotificationWithUidInternal(ctx, getAlertNotificationWithUidQuery, ss.db.NewSession(ctx)); err != nil {
|
if err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||||
|
return getAlertNotificationWithUidInternal(ctx, getAlertNotificationWithUidQuery, sess)
|
||||||
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -132,57 +132,62 @@ func TestOldAnnotationsAreDeletedFirst(t *testing.T) {
|
|||||||
Created: time.Now().AddDate(-10, 0, -10).UnixNano() / int64(time.Millisecond),
|
Created: time.Now().AddDate(-10, 0, -10).UnixNano() / int64(time.Millisecond),
|
||||||
}
|
}
|
||||||
|
|
||||||
session := fakeSQL.NewSession(context.Background())
|
err := fakeSQL.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error {
|
||||||
defer session.Close()
|
_, err := sess.Insert(a)
|
||||||
|
require.NoError(t, err, "cannot insert annotation")
|
||||||
|
_, err = sess.Insert(a)
|
||||||
|
require.NoError(t, err, "cannot insert annotation")
|
||||||
|
|
||||||
_, err := session.Insert(a)
|
a.AlertId = 20
|
||||||
require.NoError(t, err, "cannot insert annotation")
|
_, err = sess.Insert(a)
|
||||||
_, err = session.Insert(a)
|
require.NoError(t, err, "cannot insert annotation")
|
||||||
require.NoError(t, err, "cannot insert annotation")
|
|
||||||
|
|
||||||
a.AlertId = 20
|
// run the clean up task to keep one annotation.
|
||||||
_, err = session.Insert(a)
|
cfg := setting.NewCfg()
|
||||||
require.NoError(t, err, "cannot insert annotation")
|
cfg.AnnotationCleanupJobBatchSize = 1
|
||||||
|
cleaner := &xormRepositoryImpl{cfg: cfg, log: log.New("test-logger"), db: fakeSQL}
|
||||||
|
_, err = cleaner.CleanAnnotations(context.Background(), setting.AnnotationCleanupSettings{MaxCount: 1}, alertAnnotationType)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
// run the clean up task to keep one annotation.
|
// assert that the last annotations were kept
|
||||||
cfg := setting.NewCfg()
|
countNew, err := sess.Where("alert_id = 20").Count(&annotations.Item{})
|
||||||
cfg.AnnotationCleanupJobBatchSize = 1
|
require.NoError(t, err)
|
||||||
cleaner := &xormRepositoryImpl{cfg: cfg, log: log.New("test-logger"), db: fakeSQL}
|
require.Equal(t, int64(1), countNew, "the last annotations should be kept")
|
||||||
_, err = cleaner.CleanAnnotations(context.Background(), setting.AnnotationCleanupSettings{MaxCount: 1}, alertAnnotationType)
|
|
||||||
|
countOld, err := sess.Where("alert_id = 10").Count(&annotations.Item{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, int64(0), countOld, "the two first annotations should have been deleted")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// assert that the last annotations were kept
|
|
||||||
countNew, err := session.Where("alert_id = 20").Count(&annotations.Item{})
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, int64(1), countNew, "the last annotations should be kept")
|
|
||||||
|
|
||||||
countOld, err := session.Where("alert_id = 10").Count(&annotations.Item{})
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, int64(0), countOld, "the two first annotations should have been deleted")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertAnnotationCount(t *testing.T, fakeSQL *sqlstore.SQLStore, sql string, expectedCount int64) {
|
func assertAnnotationCount(t *testing.T, fakeSQL *sqlstore.SQLStore, sql string, expectedCount int64) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
session := fakeSQL.NewSession(context.Background())
|
err := fakeSQL.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error {
|
||||||
defer session.Close()
|
count, err := sess.Where(sql).Count(&annotations.Item{})
|
||||||
count, err := session.Where(sql).Count(&annotations.Item{})
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, expectedCount, count)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, expectedCount, count)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertAnnotationTagCount(t *testing.T, fakeSQL *sqlstore.SQLStore, expectedCount int64) {
|
func assertAnnotationTagCount(t *testing.T, fakeSQL *sqlstore.SQLStore, expectedCount int64) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
session := fakeSQL.NewSession(context.Background())
|
err := fakeSQL.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error {
|
||||||
defer session.Close()
|
count, err := sess.SQL("select count(*) from annotation_tag").Count()
|
||||||
|
require.NoError(t, err)
|
||||||
count, err := session.SQL("select count(*) from annotation_tag").Count()
|
require.Equal(t, expectedCount, count)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, expectedCount, count)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func createTestAnnotations(t *testing.T, sqlstore *sqlstore.SQLStore, expectedCount int, oldAnnotations int) {
|
func createTestAnnotations(t *testing.T, store *sqlstore.SQLStore, expectedCount int, oldAnnotations int) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
cutoffDate := time.Now()
|
cutoffDate := time.Now()
|
||||||
@@ -216,16 +221,19 @@ func createTestAnnotations(t *testing.T, sqlstore *sqlstore.SQLStore, expectedCo
|
|||||||
a.Created = cutoffDate.AddDate(-10, 0, -10).UnixNano() / int64(time.Millisecond)
|
a.Created = cutoffDate.AddDate(-10, 0, -10).UnixNano() / int64(time.Millisecond)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := sqlstore.NewSession(context.Background()).Insert(a)
|
err := store.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error {
|
||||||
require.NoError(t, err, "should be able to save annotation", err)
|
_, err := sess.Insert(a)
|
||||||
|
require.NoError(t, err, "should be able to save annotation", err)
|
||||||
|
|
||||||
// mimick the SQL annotation Save logic by writing records to the annotation_tag table
|
// mimick the SQL annotation Save logic by writing records to the annotation_tag table
|
||||||
// we need to ensure they get deleted when we clean up annotations
|
// we need to ensure they get deleted when we clean up annotations
|
||||||
sess := sqlstore.NewSession(context.Background())
|
for tagID := range []int{1, 2} {
|
||||||
for tagID := range []int{1, 2} {
|
_, err = sess.Exec("INSERT INTO annotation_tag (annotation_id, tag_id) VALUES(?,?)", a.Id, tagID)
|
||||||
_, err = sess.Exec("INSERT INTO annotation_tag (annotation_id, tag_id) VALUES(?,?)", a.Id, tagID)
|
require.NoError(t, err, "should be able to save annotation tag ID", err)
|
||||||
require.NoError(t, err, "should be able to save annotation tag ID", err)
|
}
|
||||||
}
|
return err
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -566,40 +566,54 @@ type testContext struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *testContext) getAuthTokenByID(id int64) (*userAuthToken, error) {
|
func (c *testContext) getAuthTokenByID(id int64) (*userAuthToken, error) {
|
||||||
sess := c.sqlstore.NewSession(context.Background())
|
var res *userAuthToken
|
||||||
var t userAuthToken
|
err := c.sqlstore.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error {
|
||||||
found, err := sess.ID(id).Get(&t)
|
var t userAuthToken
|
||||||
if err != nil || !found {
|
found, err := sess.ID(id).Get(&t)
|
||||||
return nil, err
|
if err != nil || !found {
|
||||||
}
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return &t, nil
|
res = &t
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *testContext) markAuthTokenAsSeen(id int64) (bool, error) {
|
func (c *testContext) markAuthTokenAsSeen(id int64) (bool, error) {
|
||||||
sess := c.sqlstore.NewSession(context.Background())
|
hasRowsAffected := false
|
||||||
res, err := sess.Exec("UPDATE user_auth_token SET auth_token_seen = ? WHERE id = ?", c.sqlstore.Dialect.BooleanStr(true), id)
|
err := c.sqlstore.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error {
|
||||||
if err != nil {
|
res, err := sess.Exec("UPDATE user_auth_token SET auth_token_seen = ? WHERE id = ?", c.sqlstore.Dialect.BooleanStr(true), id)
|
||||||
return false, err
|
if err != nil {
|
||||||
}
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
rowsAffected, err := res.RowsAffected()
|
rowsAffected, err := res.RowsAffected()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return err
|
||||||
}
|
}
|
||||||
return rowsAffected == 1, nil
|
hasRowsAffected = rowsAffected == 1
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return hasRowsAffected, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *testContext) updateRotatedAt(id, rotatedAt int64) (bool, error) {
|
func (c *testContext) updateRotatedAt(id, rotatedAt int64) (bool, error) {
|
||||||
sess := c.sqlstore.NewSession(context.Background())
|
hasRowsAffected := false
|
||||||
res, err := sess.Exec("UPDATE user_auth_token SET rotated_at = ? WHERE id = ?", rotatedAt, id)
|
err := c.sqlstore.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error {
|
||||||
if err != nil {
|
res, err := sess.Exec("UPDATE user_auth_token SET rotated_at = ? WHERE id = ?", rotatedAt, id)
|
||||||
return false, err
|
if err != nil {
|
||||||
}
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
rowsAffected, err := res.RowsAffected()
|
rowsAffected, err := res.RowsAffected()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return err
|
||||||
}
|
}
|
||||||
return rowsAffected == 1, nil
|
|
||||||
|
hasRowsAffected = rowsAffected == 1
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return hasRowsAffected, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -21,8 +22,12 @@ func TestUserAuthTokenCleanup(t *testing.T) {
|
|||||||
|
|
||||||
insertToken := func(ctx *testContext, token string, prev string, createdAt, rotatedAt int64) {
|
insertToken := func(ctx *testContext, token string, prev string, createdAt, rotatedAt int64) {
|
||||||
ut := userAuthToken{AuthToken: token, PrevAuthToken: prev, CreatedAt: createdAt, RotatedAt: rotatedAt, UserAgent: "", ClientIp: ""}
|
ut := userAuthToken{AuthToken: token, PrevAuthToken: prev, CreatedAt: createdAt, RotatedAt: rotatedAt, UserAgent: "", ClientIp: ""}
|
||||||
_, err := ctx.sqlstore.NewSession(context.Background()).Insert(&ut)
|
err := ctx.sqlstore.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error {
|
||||||
require.Nil(t, err)
|
_, err := sess.Insert(&ut)
|
||||||
|
require.Nil(t, err)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
now := time.Date(2018, 12, 13, 13, 45, 0, 0, time.UTC)
|
now := time.Date(2018, 12, 13, 13, 45, 0, 0, time.UTC)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||||
"github.com/grafana/grafana/pkg/services/ngalert/store"
|
"github.com/grafana/grafana/pkg/services/ngalert/store"
|
||||||
"github.com/grafana/grafana/pkg/services/ngalert/tests"
|
"github.com/grafana/grafana/pkg/services/ngalert/tests"
|
||||||
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestIntegrationSaveAndGetImage(t *testing.T) {
|
func TestIntegrationSaveAndGetImage(t *testing.T) {
|
||||||
@@ -168,30 +169,32 @@ func TestIntegrationDeleteExpiredImages(t *testing.T) {
|
|||||||
image2 := models.Image{URL: "https://example.com/example.png"}
|
image2 := models.Image{URL: "https://example.com/example.png"}
|
||||||
require.NoError(t, dbstore.SaveImage(ctx, &image2))
|
require.NoError(t, dbstore.SaveImage(ctx, &image2))
|
||||||
|
|
||||||
s := dbstore.SQLStore.NewSession(ctx)
|
err := dbstore.SQLStore.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||||
t.Cleanup(s.Close)
|
// should return both images
|
||||||
|
var result1, result2 models.Image
|
||||||
|
ok, err := sess.Where("token = ?", image1.Token).Get(&result1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.True(t, ok)
|
||||||
|
ok, err = sess.Where("token = ?", image2.Token).Get(&result2)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.True(t, ok)
|
||||||
|
|
||||||
// should return both images
|
// should delete expired image
|
||||||
var result1, result2 models.Image
|
image1.ExpiresAt = time.Now().Add(-time.Second)
|
||||||
ok, err := s.Where("token = ?", image1.Token).Get(&result1)
|
require.NoError(t, dbstore.SaveImage(ctx, &image1))
|
||||||
require.NoError(t, err)
|
n, err := dbstore.DeleteExpiredImages(ctx)
|
||||||
assert.True(t, ok)
|
require.NoError(t, err)
|
||||||
ok, err = s.Where("token = ?", image2.Token).Get(&result2)
|
assert.Equal(t, int64(1), n)
|
||||||
require.NoError(t, err)
|
|
||||||
assert.True(t, ok)
|
|
||||||
|
|
||||||
// should delete expired image
|
// should return just the second image
|
||||||
image1.ExpiresAt = time.Now().Add(-time.Second)
|
ok, err = sess.Where("token = ?", image1.Token).Get(&result1)
|
||||||
require.NoError(t, dbstore.SaveImage(ctx, &image1))
|
require.NoError(t, err)
|
||||||
n, err := dbstore.DeleteExpiredImages(ctx)
|
assert.False(t, ok)
|
||||||
require.NoError(t, err)
|
ok, err = sess.Where("token = ?", image2.Token).Get(&result2)
|
||||||
assert.Equal(t, int64(1), n)
|
require.NoError(t, err)
|
||||||
|
assert.True(t, ok)
|
||||||
|
|
||||||
// should return just the second image
|
return nil
|
||||||
ok, err = s.Where("token = ?", image1.Token).Get(&result1)
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.False(t, ok)
|
|
||||||
ok, err = s.Where("token = ?", image2.Token).Get(&result2)
|
|
||||||
require.NoError(t, err)
|
|
||||||
assert.True(t, ok)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,7 +126,9 @@ func (ss *SecretsStoreImpl) ReEncryptDataKeys(
|
|||||||
currProvider secrets.ProviderID,
|
currProvider secrets.ProviderID,
|
||||||
) error {
|
) error {
|
||||||
keys := make([]*secrets.DataKey, 0)
|
keys := make([]*secrets.DataKey, 0)
|
||||||
if err := ss.sqlStore.NewSession(ctx).Table(dataKeysTable).Find(&keys); err != nil {
|
if err := ss.sqlStore.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||||
|
return sess.Table(dataKeysTable).Find(&keys)
|
||||||
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -104,8 +104,10 @@ func (m *SecretsMigrator) RollBackSecrets(ctx context.Context) (bool, error) {
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_, sqlErr := m.sqlStore.NewSession(ctx).Exec("DELETE FROM data_keys")
|
if sqlErr := m.sqlStore.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||||
if sqlErr != nil {
|
_, err := sess.Exec("DELETE FROM data_keys")
|
||||||
|
return err
|
||||||
|
}); sqlErr != nil {
|
||||||
logger.Warn("Error while cleaning up data keys table...", "error", sqlErr)
|
logger.Warn("Error while cleaning up data keys table...", "error", sqlErr)
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ func (s simpleSecret) reencrypt(ctx context.Context, secretsSrv *manager.Secrets
|
|||||||
Secret []byte
|
Secret []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := sqlStore.NewSession(ctx).Table(s.tableName).Select(fmt.Sprintf("id, %s as secret", s.columnName)).Find(&rows); err != nil {
|
if err := sqlStore.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||||
|
return sess.Table(s.tableName).Select(fmt.Sprintf("id, %s as secret", s.columnName)).Find(&rows)
|
||||||
|
}); err != nil {
|
||||||
logger.Warn("Could not find any secret to re-encrypt", "table", s.tableName)
|
logger.Warn("Could not find any secret to re-encrypt", "table", s.tableName)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -72,7 +74,9 @@ func (s b64Secret) reencrypt(ctx context.Context, secretsSrv *manager.SecretsSer
|
|||||||
Secret string
|
Secret string
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := sqlStore.NewSession(ctx).Table(s.tableName).Select(fmt.Sprintf("id, %s as secret", s.columnName)).Find(&rows); err != nil {
|
if err := sqlStore.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||||
|
return sess.Table(s.tableName).Select(fmt.Sprintf("id, %s as secret", s.columnName)).Find(&rows)
|
||||||
|
}); err != nil {
|
||||||
logger.Warn("Could not find any secret to re-encrypt", "table", s.tableName)
|
logger.Warn("Could not find any secret to re-encrypt", "table", s.tableName)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -140,7 +144,9 @@ func (s jsonSecret) reencrypt(ctx context.Context, secretsSrv *manager.SecretsSe
|
|||||||
SecureJsonData map[string][]byte
|
SecureJsonData map[string][]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := sqlStore.NewSession(ctx).Table(s.tableName).Cols("id", "secure_json_data").Find(&rows); err != nil {
|
if err := sqlStore.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||||
|
return sess.Table(s.tableName).Cols("id", "secure_json_data").Find(&rows)
|
||||||
|
}); err != nil {
|
||||||
logger.Warn("Could not find any secret to re-encrypt", "table", s.tableName)
|
logger.Warn("Could not find any secret to re-encrypt", "table", s.tableName)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -199,7 +205,9 @@ func (s alertingSecret) reencrypt(ctx context.Context, secretsSrv *manager.Secre
|
|||||||
}
|
}
|
||||||
|
|
||||||
selectSQL := "SELECT id, alertmanager_configuration FROM alert_configuration"
|
selectSQL := "SELECT id, alertmanager_configuration FROM alert_configuration"
|
||||||
if err := sqlStore.NewSession(ctx).SQL(selectSQL).Find(&results); err != nil {
|
if err := sqlStore.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||||
|
return sess.SQL(selectSQL).Find(&results)
|
||||||
|
}); err != nil {
|
||||||
logger.Warn("Could not find any alert_configuration secret to re-encrypt")
|
logger.Warn("Could not find any alert_configuration secret to re-encrypt")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ func (s simpleSecret) rollback(
|
|||||||
Secret []byte
|
Secret []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := sqlStore.NewSession(ctx).Table(s.tableName).Select(fmt.Sprintf("id, %s as secret", s.columnName)).Find(&rows); err != nil {
|
if err := sqlStore.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||||
|
return sess.Table(s.tableName).Select(fmt.Sprintf("id, %s as secret", s.columnName)).Find(&rows)
|
||||||
|
}); err != nil {
|
||||||
logger.Warn("Could not find any secret to roll back", "table", s.tableName)
|
logger.Warn("Could not find any secret to roll back", "table", s.tableName)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -82,7 +84,9 @@ func (s b64Secret) rollback(
|
|||||||
Secret string
|
Secret string
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := sqlStore.NewSession(ctx).Table(s.tableName).Select(fmt.Sprintf("id, %s as secret", s.columnName)).Find(&rows); err != nil {
|
if err := sqlStore.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||||
|
return sess.Table(s.tableName).Select(fmt.Sprintf("id, %s as secret", s.columnName)).Find(&rows)
|
||||||
|
}); err != nil {
|
||||||
logger.Warn("Could not find any secret to roll back", "table", s.tableName)
|
logger.Warn("Could not find any secret to roll back", "table", s.tableName)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -154,7 +158,9 @@ func (s jsonSecret) rollback(
|
|||||||
SecureJsonData map[string][]byte
|
SecureJsonData map[string][]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := sqlStore.NewSession(ctx).Table(s.tableName).Cols("id", "secure_json_data").Find(&rows); err != nil {
|
if err := sqlStore.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||||
|
return sess.Table(s.tableName).Cols("id", "secure_json_data").Find(&rows)
|
||||||
|
}); err != nil {
|
||||||
logger.Warn("Could not find any secret to roll back", "table", s.tableName)
|
logger.Warn("Could not find any secret to roll back", "table", s.tableName)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -217,7 +223,9 @@ func (s alertingSecret) rollback(
|
|||||||
}
|
}
|
||||||
|
|
||||||
selectSQL := "SELECT id, alertmanager_configuration FROM alert_configuration"
|
selectSQL := "SELECT id, alertmanager_configuration FROM alert_configuration"
|
||||||
if err := sqlStore.NewSession(ctx).SQL(selectSQL).Find(&results); err != nil {
|
if err := sqlStore.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||||
|
return sess.SQL(selectSQL).Find(&results)
|
||||||
|
}); err != nil {
|
||||||
logger.Warn("Could not find any alert_configuration secret to roll back")
|
logger.Warn("Could not find any alert_configuration secret to roll back")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
type DB interface {
|
type DB interface {
|
||||||
WithTransactionalDbSession(ctx context.Context, callback sqlstore.DBTransactionFunc) error
|
WithTransactionalDbSession(ctx context.Context, callback sqlstore.DBTransactionFunc) error
|
||||||
WithDbSession(ctx context.Context, callback sqlstore.DBTransactionFunc) error
|
WithDbSession(ctx context.Context, callback sqlstore.DBTransactionFunc) error
|
||||||
NewSession(ctx context.Context) *sqlstore.DBSession
|
WithNewDbSession(ctx context.Context, callback sqlstore.DBTransactionFunc) error
|
||||||
GetDialect() migrator.Dialect
|
GetDialect() migrator.Dialect
|
||||||
GetDBType() core.DbType
|
GetDBType() core.DbType
|
||||||
GetSqlxSession() *session.SessionDB
|
GetSqlxSession() *session.SessionDB
|
||||||
|
|||||||
@@ -21,3 +21,7 @@ func (f *FakeDB) WithTransactionalDbSession(ctx context.Context, callback sqlsto
|
|||||||
func (f *FakeDB) WithDbSession(ctx context.Context, callback sqlstore.DBTransactionFunc) error {
|
func (f *FakeDB) WithDbSession(ctx context.Context, callback sqlstore.DBTransactionFunc) error {
|
||||||
return f.ExpectedError
|
return f.ExpectedError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *FakeDB) WithNewDbSession(ctx context.Context, callback sqlstore.DBTransactionFunc) error {
|
||||||
|
return f.ExpectedError
|
||||||
|
}
|
||||||
|
|||||||
@@ -222,6 +222,10 @@ func (m *SQLStoreMock) WithDbSession(ctx context.Context, callback sqlstore.DBTr
|
|||||||
return m.ExpectedError
|
return m.ExpectedError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *SQLStoreMock) WithNewDbSession(ctx context.Context, callback sqlstore.DBTransactionFunc) error {
|
||||||
|
return m.ExpectedError
|
||||||
|
}
|
||||||
|
|
||||||
func (m *SQLStoreMock) GetOrgQuotaByTarget(ctx context.Context, query *models.GetOrgQuotaByTargetQuery) error {
|
func (m *SQLStoreMock) GetOrgQuotaByTarget(ctx context.Context, query *models.GetOrgQuotaByTargetQuery) error {
|
||||||
return m.ExpectedError
|
return m.ExpectedError
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,13 +27,6 @@ func (sess *DBSession) PublishAfterCommit(msg interface{}) {
|
|||||||
sess.events = append(sess.events, msg)
|
sess.events = append(sess.events, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSession returns a new DBSession
|
|
||||||
func (ss *SQLStore) NewSession(ctx context.Context) *DBSession {
|
|
||||||
sess := &DBSession{Session: ss.engine.NewSession()}
|
|
||||||
sess.Session = sess.Session.Context(ctx)
|
|
||||||
return sess
|
|
||||||
}
|
|
||||||
|
|
||||||
func startSessionOrUseExisting(ctx context.Context, engine *xorm.Engine, beginTran bool) (*DBSession, bool, error) {
|
func startSessionOrUseExisting(ctx context.Context, engine *xorm.Engine, beginTran bool) (*DBSession, bool, error) {
|
||||||
value := ctx.Value(ContextSessionKey{})
|
value := ctx.Value(ContextSessionKey{})
|
||||||
var sess *DBSession
|
var sess *DBSession
|
||||||
@@ -55,14 +48,24 @@ func startSessionOrUseExisting(ctx context.Context, engine *xorm.Engine, beginTr
|
|||||||
}
|
}
|
||||||
|
|
||||||
newSess.Session = newSess.Session.Context(ctx)
|
newSess.Session = newSess.Session.Context(ctx)
|
||||||
|
|
||||||
return newSess, true, nil
|
return newSess, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithDbSession calls the callback with a session.
|
// WithDbSession calls the callback with the session in the context (if exists).
|
||||||
|
// Otherwise it creates a new one that is closed upon completion.
|
||||||
|
// A session is stored in the context if sqlstore.InTransaction() has been been previously called with the same context (and it's not committed/rolledback yet).
|
||||||
func (ss *SQLStore) WithDbSession(ctx context.Context, callback DBTransactionFunc) error {
|
func (ss *SQLStore) WithDbSession(ctx context.Context, callback DBTransactionFunc) error {
|
||||||
return withDbSession(ctx, ss.engine, callback)
|
return withDbSession(ctx, ss.engine, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithNewDbSession calls the callback with a new session that is closed upon completion.
|
||||||
|
func (ss *SQLStore) WithNewDbSession(ctx context.Context, callback DBTransactionFunc) error {
|
||||||
|
sess := &DBSession{Session: ss.engine.NewSession(), transactionOpen: false}
|
||||||
|
defer sess.Close()
|
||||||
|
return callback(sess)
|
||||||
|
}
|
||||||
|
|
||||||
func withDbSession(ctx context.Context, engine *xorm.Engine, callback DBTransactionFunc) error {
|
func withDbSession(ctx context.Context, engine *xorm.Engine, callback DBTransactionFunc) error {
|
||||||
sess, isNew, err := startSessionOrUseExisting(ctx, engine, false)
|
sess, isNew, err := startSessionOrUseExisting(ctx, engine, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ type Store interface {
|
|||||||
GetSignedInUser(ctx context.Context, query *models.GetSignedInUserQuery) error
|
GetSignedInUser(ctx context.Context, query *models.GetSignedInUserQuery) error
|
||||||
UpdateUserPermissions(userID int64, isAdmin bool) error
|
UpdateUserPermissions(userID int64, isAdmin bool) error
|
||||||
SetUserHelpFlag(ctx context.Context, cmd *models.SetUserHelpFlagCommand) error
|
SetUserHelpFlag(ctx context.Context, cmd *models.SetUserHelpFlagCommand) error
|
||||||
NewSession(ctx context.Context) *DBSession
|
|
||||||
WithDbSession(ctx context.Context, callback DBTransactionFunc) error
|
WithDbSession(ctx context.Context, callback DBTransactionFunc) error
|
||||||
|
WithNewDbSession(ctx context.Context, callback DBTransactionFunc) error
|
||||||
GetOrgQuotaByTarget(ctx context.Context, query *models.GetOrgQuotaByTargetQuery) error
|
GetOrgQuotaByTarget(ctx context.Context, query *models.GetOrgQuotaByTargetQuery) error
|
||||||
GetOrgQuotas(ctx context.Context, query *models.GetOrgQuotasQuery) error
|
GetOrgQuotas(ctx context.Context, query *models.GetOrgQuotasQuery) error
|
||||||
UpdateOrgQuota(ctx context.Context, cmd *models.UpdateOrgQuotaCmd) error
|
UpdateOrgQuota(ctx context.Context, cmd *models.UpdateOrgQuotaCmd) error
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ func (ss *SQLStore) WithTransactionalDbSession(ctx context.Context, callback DBT
|
|||||||
return inTransactionWithRetryCtx(ctx, ss.engine, ss.bus, callback, 0)
|
return inTransactionWithRetryCtx(ctx, ss.engine, ss.bus, callback, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InTransaction starts a transaction and calls the fn
|
||||||
|
// It stores the session in the context
|
||||||
func (ss *SQLStore) InTransaction(ctx context.Context, fn func(ctx context.Context) error) error {
|
func (ss *SQLStore) InTransaction(ctx context.Context, fn func(ctx context.Context) error) error {
|
||||||
return ss.inTransactionWithRetry(ctx, fn, 0)
|
return ss.inTransactionWithRetry(ctx, fn, 0)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user