Advertisement
cydside

Golang mattn sqlite3 driver db locks

Jun 18th, 2024 (edited)
840
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Go 3.38 KB | None | 0 0
  1.  
  2. https://groups.google.com/g/golang-nuts/c/y7WzUsMtqDA
  3. https://go.dev/play/p/tLjXXcHq5H
  4.  
  5. package main
  6.  
  7. import (
  8.     "fmt"
  9.     "math/rand"
  10.     "sync"
  11.     "time"
  12. )
  13.  
  14. func main() {
  15.     launchSomeFakeQueries()
  16. }
  17.  
  18. var mutexes = map[string]*sync.Mutex{}
  19. var globalMapGuard sync.Mutex
  20.  
  21. //
  22. // Protect the global map.
  23. // Any accesses to the global map MUST lock the global mutex and then MUST return very quickly
  24. //
  25.  
  26. func getMutex(dbpath string) *sync.Mutex {
  27.     globalMapGuard.Lock()
  28.     defer globalMapGuard.Unlock()
  29.  
  30.     if mutex, exists := mutexes[dbpath]; exists {
  31.         return mutex
  32.     }
  33.     var newMutex sync.Mutex
  34.     mutexes[dbpath] = &newMutex
  35.     return &newMutex
  36. }
  37.  
  38. //
  39. // Execute some (potentially long) query on a specific DB
  40. //
  41.  
  42. func executeGuardedQuery(dbpath string, q func(string)) {
  43.     mutex := getMutex(dbpath)
  44.     mutex.Lock()
  45.     defer mutex.Unlock()
  46.  
  47.     q(dbpath)
  48. }
  49.  
  50. func launchSomeFakeQueries() {
  51.     var wg sync.WaitGroup
  52.     for i := 0; i < 25; i++ {
  53.         dbpath := fmt.Sprintf("file%d.sqlite", rand.Intn(5))
  54.         duration := time.Duration(rand.Intn(100)) * time.Millisecond
  55.         wg.Add(1)
  56.         go executeGuardedQuery(dbpath, func(dbpath string) {
  57.             fmt.Println("Starting some work on", dbpath)
  58.             time.Sleep(duration)
  59.             fmt.Println("Finished some work on", dbpath)
  60.             wg.Done()
  61.         })
  62.     }
  63.     wg.Wait()
  64. }
  65.  
  66. https://sqlite.org/wal.html#concurrency
  67.  
  68. https://stackoverflow.com/questions/36431452/precautions-to-avoid-sqlite-file-database-locks-when-concurrent-goroutines-try-t
  69.  
  70. https://www.reddit.com/r/golang/comments/1988ch8/database_is_locked_when_writing_sqlite3_interface/
  71.  
  72.  
  73. https://github.com/mattn/go-sqlite3/issues/209
  74.  
  75. https://gist.github.com/davyzhang/1392344f993eac471c90
  76.  
  77. package main
  78.  
  79. import (
  80.     "database/sql"
  81.     "fmt"
  82.     "log"
  83.     "os"
  84.  
  85.     _ "github.com/mattn/go-sqlite3"
  86. )
  87.  
  88. func main() {
  89.     os.Remove("/tmp/testlock.db")
  90.     os.Remove("/tmp/testlock-shm.db")
  91.     os.Remove("/tmp/testlock-wal.db")
  92.  
  93.     var db *sql.DB
  94.     if len(os.Args) != 2 { //no param
  95.         printUsage()
  96.         return
  97.     }
  98.     switch os.Args[1] {
  99.     case "1":
  100.         db = openDB()
  101.         initDB(db)
  102.     case "0":
  103.         dbLoc := openDB()
  104.         initDB(dbLoc)
  105.         dbLoc.Close()
  106.     default:
  107.         printUsage()
  108.         return
  109.     }
  110.  
  111.     ch := make(chan bool)
  112.     go writer(db)
  113.     go reader(db)
  114.     <-ch
  115. }
  116.  
  117. func printUsage() {
  118.     fmt.Printf("usage: dbtest mode\n 0:multiple connection; 1:single connection\n")
  119. }
  120.  
  121. func initDB(db *sql.DB) {
  122.     sSql := `
  123.         CREATE TABLE counters (
  124.             id      INTEGER,
  125.             intro         VARCHAR (255)
  126.         )`
  127.     db.Exec(sSql)
  128. }
  129.  
  130. func openDB() *sql.DB {
  131.     db, err := sql.Open("sqlite3", "file:/tmp/testlock.db?cache=shared&mode=rwc&_busy_timeout=9999999")
  132.     if err != nil {
  133.         log.Printf("open error %s", err)
  134.         return nil
  135.     }
  136.     db.Exec("PRAGMA journal_mode=WAL")
  137.     return db
  138. }
  139.  
  140. func writer(db *sql.DB) {
  141.     var dbLoc *sql.DB
  142.     if db == nil {
  143.         dbLoc = openDB()
  144.     } else {
  145.         dbLoc = db
  146.     }
  147.     sSql := `
  148.         INSERT INTO counters (
  149.             id,intro
  150.         ) VALUES(
  151.             ?,?
  152.         )`
  153.     dbLoc.Exec(sSql, 1, "")
  154.     i := 0
  155.     sSql = `
  156.     update counters set id = ?
  157.     `
  158.     for {
  159.         _, err := dbLoc.Exec(sSql, i)
  160.         i += 1
  161.         if err != nil {
  162.             log.Printf("db error in writer %s", err)
  163.             os.Exit(1)
  164.         }
  165.     }
  166. }
  167.  
  168. func reader(db *sql.DB) {
  169.     var dbLoc *sql.DB
  170.     if db == nil {
  171.         dbLoc = openDB()
  172.     } else {
  173.         dbLoc = db
  174.     }
  175.     sSql := `
  176.     select * from counters
  177.     `
  178.     for {
  179.         _, err := dbLoc.Exec(sSql)
  180.         if err != nil {
  181.             log.Printf("db error in reader %s", err)
  182.             os.Exit(1)
  183.         }
  184.     }
  185. }
  186.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement