Skip to content

Commit

Permalink
Merge pull request #18 from doug-martin/race_cond
Browse files Browse the repository at this point in the history
Fixing race condition with struct_map_cache in crud_exec
  • Loading branch information
aheuermann committed Oct 23, 2015
2 parents d2494e1 + 728009a commit cd0a6f0
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@ before_script:
- mv -vfT $DEFAULT_TRAVIS_BUILD_DIR $TRAVIS_BUILD_DIR
- psql -c 'create database goqupostgres;' -U postgres
- mysql -e 'create database goqumysql;'

script: go test -v -race ./...
5 changes: 5 additions & 0 deletions crud_exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"reflect"
"strings"
"sync"
)

type (
Expand All @@ -25,6 +26,7 @@ type (
)

var struct_map_cache = make(map[interface{}]columnMap)
var struct_map_cache_lock = sync.Mutex{}

func newCrudExec(database database, err error, sql string, args ...interface{}) *CrudExec {
return &CrudExec{database: database, err: err, Sql: sql, Args: args}
Expand Down Expand Up @@ -278,6 +280,9 @@ func getColumnMap(i interface{}) (columnMap, error) {
if valKind != reflect.Struct {
return nil, NewGoquError(fmt.Sprintf("Cannot SELECT into this type: %v", t))
}

struct_map_cache_lock.Lock()
defer struct_map_cache_lock.Unlock()
if _, ok := struct_map_cache[t]; !ok {
struct_map_cache[t] = createColumnMap(t)
}
Expand Down
34 changes: 33 additions & 1 deletion crud_exec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ package goqu

import (
"fmt"
"sync"
"testing"

"gopkg.in/DATA-DOG/go-sqlmock.v1"
"github.com/c2fo/testify/assert"
"github.com/c2fo/testify/suite"
"gopkg.in/DATA-DOG/go-sqlmock.v1"
)

type testCrudActionItem struct {
Expand Down Expand Up @@ -265,6 +266,37 @@ func (me *crudExecTest) TestScanVal() {
assert.Equal(t, ptrId, 1)
}

func (me *crudExecTest) TestParallelGetColumnMap() {
t := me.T()

type item struct {
id uint
name string
}

wg := sync.WaitGroup{}

wg.Add(1)
go func() {
i := item{}
m, err := getColumnMap(i)
assert.NoError(t, err)
assert.NotNil(t, m)
wg.Done()
}()

wg.Add(1)
go func() {
i := item{}
m, err := getColumnMap(i)
assert.NoError(t, err)
assert.NotNil(t, m)
wg.Done()
}()

wg.Wait()
}

func TestCrudExecSuite(t *testing.T) {
suite.Run(t, new(crudExecTest))
}

0 comments on commit cd0a6f0

Please sign in to comment.