Merge pull request #330 from ericchiang/mem_db_concurrent_conns

db: only allow one open connection for in memory databases
This commit is contained in:
Eric Chiang 2016-02-25 13:23:08 -08:00
commit 4855805983
2 changed files with 47 additions and 1 deletions

View file

@ -67,7 +67,14 @@ func NewConnection(cfg Config) (*gorp.DbMap, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
// NOTE(ericchiang): sqlite does NOT work with SetMaxIdleConns. if u.Host == ":memory:" {
// NOTE(ericchiang): sqlite3 coordinates concurrent clients through file locks.
// In memory databases do not support concurrent calls. Limit the number of
// open connections to 1.
//
// See: https://www.sqlite.org/faq.html#q5
db.SetMaxOpenConns(1)
}
dialect = gorp.SqliteDialect{} dialect = gorp.SqliteDialect{}
default: default:
return nil, errors.New("unrecognized database driver") return nil, errors.New("unrecognized database driver")

39
db/conn_test.go Normal file
View file

@ -0,0 +1,39 @@
package db
import (
"sync"
"testing"
"github.com/coreos/dex/connector"
)
// TestConcurrentSqliteConns tests concurrent writes to a single in memory database.
func TestConcurrentSqliteConns(t *testing.T) {
dbMap := NewMemDB()
repo := NewConnectorConfigRepo(dbMap)
var (
once sync.Once
wg sync.WaitGroup
)
n := 1000
wg.Add(n)
for i := 0; i < n; i++ {
go func() {
configs := []connector.ConnectorConfig{
&connector.LocalConnectorConfig{ID: "local"},
}
// Setting connector configs both deletes and writes to a single table
// within a transaction.
if err := repo.Set(configs); err != nil {
// Don't print 1000 errors, only the first.
once.Do(func() {
t.Errorf("concurrent connections to sqlite3: %v", err)
})
}
wg.Done()
}()
}
wg.Wait()
}