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:
Sofia Papagiannaki
2022-09-29 15:55:47 +03:00
committed by GitHub
parent c9e957a44e
commit 8b77ee2734
19 changed files with 289 additions and 210 deletions
+52 -51
View File
@@ -54,36 +54,38 @@ func (dc *databaseCache) internalRunGC() {
func (dc *databaseCache) Get(ctx context.Context, key string) (interface{}, error) {
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{}
if err = decodeGob(cacheHit.Data, item); err != nil {
return nil, err
}
err := dc.SQLStore.WithDbSession(ctx, func(session *sqlstore.DBSession) error {
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 {
@@ -93,34 +95,33 @@ func (dc *databaseCache) Set(ctx context.Context, key string, value interface{},
return err
}
session := dc.SQLStore.NewSession(context.Background())
defer session.Close()
return dc.SQLStore.WithDbSession(ctx, func(session *sqlstore.DBSession) error {
var expiresInSeconds int64
if expire != 0 {
expiresInSeconds = int64(expire) / int64(time.Second)
}
var expiresInSeconds int64
if expire != 0 {
expiresInSeconds = int64(expire) / int64(time.Second)
}
// attempt to insert the key
sql := `INSERT INTO cache_data (cache_key,data,created_at,expires) VALUES(?,?,?,?)`
_, 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
// if the update fails propagate the error
// which eventually will result in a key that is not finally set
// but since it's a cache does not harm a lot
if dc.SQLStore.Dialect.IsUniqueConstraintViolation(err) || dc.SQLStore.Dialect.IsDeadlock(err) {
sql := `UPDATE cache_data SET data=?, created_at=?, expires=? WHERE cache_key=?`
_, 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
// attempt to insert the key
sql := `INSERT INTO cache_data (cache_key,data,created_at,expires) VALUES(?,?,?,?)`
_, 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
// if the update fails propagate the error
// which eventually will result in a key that is not finally set
// but since it's a cache does not harm a lot
if dc.SQLStore.Dialect.IsUniqueConstraintViolation(err) || dc.SQLStore.Dialect.IsDeadlock(err) {
sql := `UPDATE cache_data SET data=?, created_at=?, expires=? WHERE cache_key=?`
_, 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 {