Skip to content

Reading via a large number of goroutines breaks #289

Closed
@anantn

Description

@anantn

Reading from more than ~1000 goroutines simultaneously fails with an error "unable to open database file". Test program is attached. You can tweak maxRoutines to see the normal/broken behavior, on my local tests everything works fine until about 1000 goroutines.

package main

import (
    "database/sql"
    "fmt"
    "log"
    "math/rand"
    "os"
    "sync"

    _ "github.com/mattn/go-sqlite3"
)

const (
    maxKeys     = 20
    maxRoutines = 5000
)

func main() {
    // Create DB.
    os.Remove("./test.db")
    destDb, err := sql.Open("sqlite3", "./test.db")
    if err != nil {
        log.Fatal(err)
    }
    defer destDb.Close()
    destDb.Ping()

    // Create table.
    _, err = destDb.Exec("create table test(id int, value text)")
    if err != nil {
        log.Fatal(err)
    }

    // Write 20 values.
    for i := 0; i < maxKeys; i++ {
        _, err = destDb.Exec(fmt.Sprintf("insert into test values(%d, 'random_value')", i))
        if err != nil {
            log.Fatal(err)
        }
    }

    // Now test.
    stressTest(destDb)
    fmt.Printf("Success!\n")
}

func stressTest(db *sql.DB) {
    // Read values from all of these simultaneously.
    var wg sync.WaitGroup
    for i := 0; i < maxRoutines; i++ {
        wg.Add(1)
        go read(i, db, &wg)
    }
    wg.Wait()
}

func read(num int, db *sql.DB, wg *sync.WaitGroup) {
    defer wg.Done()
    _, err := db.Query(fmt.Sprintf("select value from test where id=%d", rand.Intn(maxKeys)))
    if err != nil {
        fmt.Printf("Goroutine %d failed read : %v\n", num, err)
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions