Skip to content

Commit

Permalink
feat: Moving cache to internal (#3192)
Browse files Browse the repository at this point in the history
  • Loading branch information
yhakbar authored Jun 11, 2024
1 parent 817f1e9 commit b5098b0
Show file tree
Hide file tree
Showing 8 changed files with 175 additions and 77 deletions.
40 changes: 0 additions & 40 deletions config/cache.go

This file was deleted.

34 changes: 3 additions & 31 deletions config/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,14 @@ package config
import (
"testing"

"github.com/gruntwork-io/terragrunt/internal/cache"
"github.com/stretchr/testify/assert"
)

func TestStringCacheCreation(t *testing.T) {
t.Parallel()

cache := NewCache[string]()

assert.NotNil(t, cache.Mutex)
assert.NotNil(t, cache.Cache)

assert.Equal(t, 0, len(cache.Cache))
}

func TestStringCacheOperation(t *testing.T) {
t.Parallel()

cache := NewCache[string]()

value, found := cache.Get("potato")

assert.False(t, found)
assert.Empty(t, value)

cache.Put("potato", "carrot")
value, found = cache.Get("potato")

assert.True(t, found)
assert.NotEmpty(t, value)
assert.Equal(t, "carrot", value)
}

func TestTerragruntConfigCacheCreation(t *testing.T) {
t.Parallel()

cache := NewCache[TerragruntConfig]()
cache := cache.NewCache[TerragruntConfig]()

assert.NotNil(t, cache.Mutex)
assert.NotNil(t, cache.Cache)
Expand All @@ -51,7 +23,7 @@ func TestTerragruntConfigCacheOperation(t *testing.T) {

testCacheKey := "super-safe-cache-key"

cache := NewCache[TerragruntConfig]()
cache := cache.NewCache[TerragruntConfig]()

actualResult, found := cache.Get(testCacheKey)

Expand Down
5 changes: 3 additions & 2 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"path/filepath"
"strings"

"github.com/gruntwork-io/terragrunt/internal/cache"
"github.com/gruntwork-io/terragrunt/telemetry"

"github.com/mitchellh/mapstructure"
Expand Down Expand Up @@ -682,7 +683,7 @@ func ReadTerragruntConfig(terragruntOptions *options.TerragruntOptions) (*Terrag
return ParseConfigFile(terragruntOptions, ctx, terragruntOptions.TerragruntConfigPath, nil)
}

var hclCache = NewCache[*hclparse.File]()
var hclCache = cache.NewCache[*hclparse.File]()

// Parse the Terragrunt config file at the given path. If the include parameter is not nil, then treat this as a config
// included in some other config file when resolving relative paths.
Expand Down Expand Up @@ -843,7 +844,7 @@ func ParseConfig(ctx *ParsingContext, file *hclparse.File, includeFromChild *Inc
}

// iamRoleCache - store for cached values of IAM roles
var iamRoleCache = NewCache[options.IAMRoleOptions]()
var iamRoleCache = cache.NewCache[options.IAMRoleOptions]()

// setIAMRole - extract IAM role details from Terragrunt flags block
func setIAMRole(ctx *ParsingContext, file *hclparse.File, includeFromChild *IncludeConfig) error {
Expand Down
5 changes: 3 additions & 2 deletions config/config_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/gruntwork-io/go-commons/errors"
"github.com/gruntwork-io/terragrunt/aws_helper"
"github.com/gruntwork-io/terragrunt/config/hclparse"
"github.com/gruntwork-io/terragrunt/internal/cache"
"github.com/gruntwork-io/terragrunt/options"
"github.com/gruntwork-io/terragrunt/shell"
"github.com/gruntwork-io/terragrunt/terraform"
Expand Down Expand Up @@ -309,7 +310,7 @@ func parseGetEnvParameters(parameters []string) (EnvVar, error) {

// runCommandCache - cache of evaluated `run_cmd` invocations
// see: https://github.com/gruntwork-io/terragrunt/issues/1427
var runCommandCache = NewCache[string]()
var runCommandCache = cache.NewCache[string]()

// runCommand is a helper function that runs a command and returns the stdout as the interporation
// for each `run_cmd` in locals section, function is called twice
Expand Down Expand Up @@ -727,7 +728,7 @@ func getModulePathFromSourceUrl(sourceUrl string) (string, error) {
//
// The cache keys are the canonical paths to the encrypted files, and the values are the
// plain-text result of the decrypt operation.
var sopsCache = NewCache[string]()
var sopsCache = cache.NewCache[string]()

// decrypts and returns sops encrypted utf-8 yaml or json data as a string
func sopsDecryptFile(ctx *ParsingContext, params []string) (string, error) {
Expand Down
3 changes: 2 additions & 1 deletion config/config_partial.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/gruntwork-io/go-commons/errors"
"github.com/gruntwork-io/terragrunt/config/hclparse"
"github.com/gruntwork-io/terragrunt/internal/cache"
"github.com/gruntwork-io/terragrunt/util"
)

Expand Down Expand Up @@ -142,7 +143,7 @@ func PartialParseConfigFile(ctx *ParsingContext, configPath string, include *Inc
return TerragruntConfigFromPartialConfig(ctx, file, include)
}

var terragruntConfigCache = NewCache[TerragruntConfig]()
var terragruntConfigCache = cache.NewCache[TerragruntConfig]()

// Wrapper of PartialParseConfigString which checks for cached configs.
// filename, configString, includeFromChild and decodeList are used for the cache key,
Expand Down
3 changes: 2 additions & 1 deletion configstack/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"sort"
"strings"

"github.com/gruntwork-io/terragrunt/internal/cache"
"github.com/gruntwork-io/terragrunt/telemetry"

"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -466,7 +467,7 @@ func resolveExternalDependenciesForModules(ctx context.Context, moduleMap map[st
return allExternalDependencies, nil
}

var existingModules = config.NewCache[*map[string]*TerraformModule]()
var existingModules = cache.NewCache[*map[string]*TerraformModule]()

// resolveDependenciesForModule looks through the dependencies of the given module and resolve the dependency paths listed in the module's config.
// If `skipExternal` is true, the func returns only dependencies that are inside of the current working directory, which means they are part of the environment the
Expand Down
83 changes: 83 additions & 0 deletions internal/cache/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package cache

import (
"crypto/sha256"
"fmt"
"sync"
"time"
)

// Cache - generic cache implementation
type Cache[V any] struct {
Cache map[string]V
Mutex *sync.Mutex
}

// NewCache - create new cache with generic type V
func NewCache[V any]() *Cache[V] {
return &Cache[V]{
Cache: make(map[string]V),
Mutex: &sync.Mutex{},
}
}

// Get - fetch value from cache by key
func (c *Cache[V]) Get(key string) (V, bool) {
c.Mutex.Lock()
defer c.Mutex.Unlock()
keyHash := sha256.Sum256([]byte(key))
cacheKey := fmt.Sprintf("%x", keyHash)
value, found := c.Cache[cacheKey]
return value, found
}

// Put - put value into cache by key
func (c *Cache[V]) Put(key string, value V) {
c.Mutex.Lock()
defer c.Mutex.Unlock()
keyHash := sha256.Sum256([]byte(key))
cacheKey := fmt.Sprintf("%x", keyHash)
c.Cache[cacheKey] = value
}

// ExpiringItem - item with expiration time
type ExpiringItem[V any] struct {
Value V
Expiration time.Time
}

// ExpiringCache - cache with items with expiration time
type ExpiringCache[V any] struct {
Cache map[string]ExpiringItem[V]
Mutex *sync.Mutex
}

// NewExpiringCache - create new cache with generic type V
func NewExpiringCache[V any]() *ExpiringCache[V] {
return &ExpiringCache[V]{
Cache: make(map[string]ExpiringItem[V]),
Mutex: &sync.Mutex{},
}
}

// Get - fetch value from cache by key
func (c *ExpiringCache[V]) Get(key string) (V, bool) {
c.Mutex.Lock()
defer c.Mutex.Unlock()
item, found := c.Cache[key]
if !found {
return item.Value, false
}
if time.Now().After(item.Expiration) {
delete(c.Cache, key)
return item.Value, false
}
return item.Value, true
}

// Put - put value into cache by key
func (c *ExpiringCache[V]) Put(key string, value V, expiration time.Time) {
c.Mutex.Lock()
defer c.Mutex.Unlock()
c.Cache[key] = ExpiringItem[V]{Value: value, Expiration: expiration}
}
79 changes: 79 additions & 0 deletions internal/cache/cache_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package cache

import (
"testing"
"time"

"github.com/stretchr/testify/assert"
)

func TestCacheCreation(t *testing.T) {
t.Parallel()

cache := NewCache[string]()

assert.NotNil(t, cache.Mutex)
assert.NotNil(t, cache.Cache)

assert.Equal(t, 0, len(cache.Cache))
}

func TestStringCacheOperation(t *testing.T) {
t.Parallel()

cache := NewCache[string]()

value, found := cache.Get("potato")

assert.False(t, found)
assert.Empty(t, value)

cache.Put("potato", "carrot")
value, found = cache.Get("potato")

assert.True(t, found)
assert.NotEmpty(t, value)
assert.Equal(t, "carrot", value)
}

func TestExpiringCacheCreation(t *testing.T) {
t.Parallel()

cache := NewExpiringCache[string]()

assert.NotNil(t, cache.Mutex)
assert.NotNil(t, cache.Cache)

assert.Equal(t, 0, len(cache.Cache))
}

func TestExpiringCacheOperation(t *testing.T) {
t.Parallel()

cache := NewExpiringCache[string]()

value, found := cache.Get("potato")

assert.False(t, found)
assert.Empty(t, value)

cache.Put("potato", "carrot", time.Now().Add(1*time.Second))
value, found = cache.Get("potato")

assert.True(t, found)
assert.NotEmpty(t, value)
assert.Equal(t, "carrot", value)
}

func TestExpiringCacheExpiration(t *testing.T) {
t.Parallel()

cache := NewExpiringCache[string]()

cache.Put("potato", "carrot", time.Now().Add(-1*time.Second))
value, found := cache.Get("potato")

assert.False(t, found)
assert.NotEmpty(t, value)
assert.Equal(t, "carrot", value)
}

0 comments on commit b5098b0

Please sign in to comment.