cue/cuecontext: allow concurrent use
This was currently only not allowed for imports.
Really import indices should be unique per context, but
even in that case, concurrency should be allowed.
Fixes #1414
Signed-off-by: Marcel van Lohuizen <mpvl@golang.org>
Change-Id: I944357c7b68cd242d19b323a1380c751a7fe49a5
Signed-off-by: Marcel van Lohuizen <mpvl@golang.org>
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/529629
Reviewed-by: Paul Jolly <paul@myitcv.io>
diff --git a/cue/cuecontext/cuecontext_test.go b/cue/cuecontext/cuecontext_test.go
index 2a780aa..aa5444a 100644
--- a/cue/cuecontext/cuecontext_test.go
+++ b/cue/cuecontext/cuecontext_test.go
@@ -54,3 +54,21 @@
})
}
}
+
+// TestConcurrency tests whether concurrent use of an index is allowed.
+// This test only functions well with the --race flag.
+func TestConcurrency(t *testing.T) {
+ c := New()
+ go func() {
+ c.CompileString(`
+ package foo
+ a: 1
+ `)
+ }()
+ go func() {
+ c.CompileString(`
+ package bar
+ a: 2
+ `)
+ }()
+}
diff --git a/internal/core/runtime/build.go b/internal/core/runtime/build.go
index e3fb7ab..da5634b 100644
--- a/internal/core/runtime/build.go
+++ b/internal/core/runtime/build.go
@@ -135,7 +135,7 @@
return nil // TODO: check the builtin package exists here.
}
- if v := x.index.importsByBuild[pkg]; v != nil {
+ if v := x.getNodeFromInstance(pkg); v != nil {
return pkg.Err
}
diff --git a/internal/core/runtime/imports.go b/internal/core/runtime/imports.go
index 243db4f..403a8a0 100644
--- a/internal/core/runtime/imports.go
+++ b/internal/core/runtime/imports.go
@@ -58,13 +58,17 @@
//
// All instances belonging to the same package should share this index.
type index struct {
- // Change this to Instance at some point.
- // From *structLit/*Vertex -> Instance
+ // lock is used to guard imports-related maps.
+ // TODO: makes these per cuecontext.
+ lock sync.RWMutex
imports map[*adt.Vertex]*build.Instance
importsByPath map[string]*adt.Vertex
importsByBuild map[*build.Instance]*adt.Vertex
- builtinPaths map[string]PackageFunc // Full path
- builtinShort map[string]string // Commandline shorthand
+
+ // These are initialized during Go package initialization time and do not
+ // need to be guarded.
+ builtinPaths map[string]PackageFunc // Full path
+ builtinShort map[string]string // Commandline shorthand
typeCache sync.Map // map[reflect.Type]evaluated
}
@@ -86,6 +90,9 @@
}
func (r *Runtime) AddInst(path string, key *adt.Vertex, p *build.Instance) {
+ r.index.lock.Lock()
+ defer r.index.lock.Unlock()
+
x := r.index
if key == nil {
panic("key must not be nil")
@@ -98,14 +105,23 @@
}
func (r *Runtime) GetInstanceFromNode(key *adt.Vertex) *build.Instance {
+ r.index.lock.RLock()
+ defer r.index.lock.RUnlock()
+
return r.index.imports[key]
}
func (r *Runtime) getNodeFromInstance(key *build.Instance) *adt.Vertex {
+ r.index.lock.RLock()
+ defer r.index.lock.RUnlock()
+
return r.index.importsByBuild[key]
}
func (r *Runtime) LoadImport(importPath string) (*adt.Vertex, errors.Error) {
+ r.index.lock.Lock()
+ defer r.index.lock.Unlock()
+
x := r.index
key := x.importsByPath[importPath]