shared.go 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. package sqlstore
  2. import (
  3. "time"
  4. "github.com/go-xorm/xorm"
  5. "github.com/grafana/grafana/pkg/bus"
  6. "github.com/grafana/grafana/pkg/log"
  7. sqlite3 "github.com/mattn/go-sqlite3"
  8. )
  9. type dbTransactionFunc func(sess *xorm.Session) error
  10. type dbTransactionFunc2 func(sess *session) error
  11. type session struct {
  12. *xorm.Session
  13. events []interface{}
  14. }
  15. func (sess *session) publishAfterCommit(msg interface{}) {
  16. sess.events = append(sess.events, msg)
  17. }
  18. func inTransaction(callback dbTransactionFunc) error {
  19. return inTransactionWithRetry(callback, 0)
  20. }
  21. func inTransactionWithRetry(callback dbTransactionFunc, retry int) error {
  22. var err error
  23. sess := x.NewSession()
  24. defer sess.Close()
  25. if err = sess.Begin(); err != nil {
  26. return err
  27. }
  28. err = callback(sess)
  29. // special handling of database locked errors for sqlite, then we can retry 3 times
  30. if sqlError, ok := err.(sqlite3.Error); ok && retry < 5 {
  31. if sqlError.Code == sqlite3.ErrLocked {
  32. sess.Rollback()
  33. time.Sleep(time.Millisecond * time.Duration(10))
  34. sqlog.Info("Database table locked, sleeping then retrying", "retry", retry)
  35. return inTransactionWithRetry(callback, retry+1)
  36. }
  37. }
  38. if err != nil {
  39. sess.Rollback()
  40. return err
  41. } else if err = sess.Commit(); err != nil {
  42. return err
  43. }
  44. return nil
  45. }
  46. func inTransaction2(callback dbTransactionFunc2) error {
  47. var err error
  48. sess := session{Session: x.NewSession()}
  49. defer sess.Close()
  50. if err = sess.Begin(); err != nil {
  51. return err
  52. }
  53. err = callback(&sess)
  54. if err != nil {
  55. sess.Rollback()
  56. return err
  57. } else if err = sess.Commit(); err != nil {
  58. return err
  59. }
  60. if len(sess.events) > 0 {
  61. for _, e := range sess.events {
  62. if err = bus.Publish(e); err != nil {
  63. log.Error(3, "Failed to publish event after commit", err)
  64. }
  65. }
  66. }
  67. return nil
  68. }