Skip to content

Commit

Permalink
terraform/schema: Swap mutex for semaphore
Browse files Browse the repository at this point in the history
  • Loading branch information
radeksimko committed Mar 16, 2020
1 parent e8dc338 commit ef59087
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 9 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ require (
github.com/mitchellh/cli v1.0.0
github.com/sourcegraph/go-lsp v0.0.0-20200117082640-b19bb38222e2
github.com/zclconf/go-cty v1.2.1
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 // indirect
golang.org/x/text v0.3.2
)
Expand Down
31 changes: 22 additions & 9 deletions internal/terraform/schema/schema_storage.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package schema

import (
"context"
"fmt"
"io/ioutil"
"log"
"sync"
"time"

"github.com/hashicorp/go-version"
tfjson "github.com/hashicorp/terraform-json"
"github.com/hashicorp/terraform-ls/internal/terraform/exec"
"golang.org/x/sync/semaphore"
)

type Reader interface {
Expand All @@ -29,9 +30,9 @@ type Storage struct {

logger *log.Logger

// mu ensures atomic reading and obtaining of schemas
// sem ensures atomic reading and obtaining of schemas
// as the process of obtaining it may not be thread-safe
mu sync.RWMutex
sem *semaphore.Weighted

// sync makes operations synchronous which makes testing easier
sync bool
Expand All @@ -42,6 +43,7 @@ var defaultLogger = log.New(ioutil.Discard, "", 0)
func NewStorage() *Storage {
return &Storage{
logger: defaultLogger,
sem: semaphore.NewWeighted(1),
}
}

Expand Down Expand Up @@ -70,9 +72,12 @@ func (s *Storage) ObtainSchemasForWorkspace(tf *exec.Executor, dir string) error
}

func (s *Storage) obtainSchemasForWorkspace(tf *exec.Executor, dir string) error {
s.logger.Printf("Obtaining lock before retrieving schema for %q ...", dir)
s.mu.Lock()
defer s.mu.Unlock()
s.logger.Printf("Acquiring semaphore before retrieving schema for %q ...", dir)
err := s.sem.Acquire(context.Background(), 1)
if err != nil {
return fmt.Errorf("failed to acquire semaphore: %w", err)
}
defer s.sem.Release(1)

// Checking the version here may be excessive
// TODO: Find a way to centralize this
Expand All @@ -99,11 +104,19 @@ func (s *Storage) obtainSchemasForWorkspace(tf *exec.Executor, dir string) error
}

func (s *Storage) ProviderConfigSchema(name string) (*tfjson.Schema, error) {
s.logger.Printf("Obtaining lock before reading %q provider schema", name)
s.mu.RLock()
defer s.mu.RUnlock()
s.logger.Printf("Acquiring semaphore before reading %q provider schema", name)
acquired := s.sem.TryAcquire(1)
if !acquired {
return nil, fmt.Errorf("schema unavailable temporarily")
}
defer s.sem.Release(1)

s.logger.Printf("Reading %q provider schema", name)

if s.ps == nil {
return nil, &SchemaUnavailableErr{"provider", name}
}

schema, ok := s.ps.Schemas[name]
if !ok {
return nil, &SchemaUnavailableErr{"provider", name}
Expand Down

0 comments on commit ef59087

Please sign in to comment.