Skip to content

Commit 3721247

Browse files
committed
chore: add cacheCloser to cleanup all opened files
1 parent 9b5d499 commit 3721247

File tree

3 files changed

+76
-16
lines changed

3 files changed

+76
-16
lines changed

coderd/dynamicparameters/render.go

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -131,46 +131,48 @@ func (r *loader) Renderer(ctx context.Context, db database.Store, cache *files.C
131131
return r.staticRender(ctx, db)
132132
}
133133

134-
return r.dynamicRenderer(ctx, db, cache)
134+
return r.dynamicRenderer(ctx, db, files.NewCacheCloser(cache))
135135
}
136136

137137
// Renderer caches all the necessary files when rendering a template version's
138138
// parameters. It must be closed after use to release the cached files.
139-
func (r *loader) dynamicRenderer(ctx context.Context, db database.Store, cache *files.Cache) (*dynamicRenderer, error) {
139+
func (r *loader) dynamicRenderer(ctx context.Context, db database.Store, cache *files.CacheCloser) (*dynamicRenderer, error) {
140+
closeFiles := true // If the function returns with no error, this will toggle to false.
141+
defer func() {
142+
if closeFiles {
143+
cache.Close()
144+
}
145+
}()
146+
140147
// If they can read the template version, then they can read the file for
141148
// parameter loading purposes.
142149
//nolint:gocritic
143150
fileCtx := dbauthz.AsFileReader(ctx)
144-
templateFS, err := cache.Acquire(fileCtx, r.job.FileID)
151+
152+
var templateFS fs.FS
153+
var err error
154+
155+
templateFS, err = cache.Acquire(fileCtx, r.job.FileID)
145156
if err != nil {
146157
return nil, xerrors.Errorf("acquire template file: %w", err)
147158
}
148159

149-
var terraformFS fs.FS = templateFS
150160
var moduleFilesFS *files.CloseFS
151161
if r.terraformValues.CachedModuleFiles.Valid {
152162
moduleFilesFS, err = cache.Acquire(fileCtx, r.terraformValues.CachedModuleFiles.UUID)
153163
if err != nil {
154-
templateFS.Close()
155164
return nil, xerrors.Errorf("acquire module files: %w", err)
156165
}
157-
terraformFS = files.NewOverlayFS(templateFS, []files.Overlay{{Path: ".terraform/modules", FS: moduleFilesFS}})
166+
templateFS = files.NewOverlayFS(templateFS, []files.Overlay{{Path: ".terraform/modules", FS: moduleFilesFS}})
158167
}
159168

169+
closeFiles = false // Caller will have to call close
160170
return &dynamicRenderer{
161171
data: r,
162-
templateFS: terraformFS,
172+
templateFS: templateFS,
163173
db: db,
164174
ownerErrors: make(map[uuid.UUID]error),
165-
close: func() {
166-
// Up to 2 files are cached, and must be released when rendering is complete.
167-
// TODO: Might be smart to always call release when the context is
168-
// canceled.
169-
templateFS.Close()
170-
if moduleFilesFS != nil {
171-
moduleFilesFS.Close()
172-
}
173-
},
175+
close: cache.Close,
174176
}, nil
175177
}
176178

coderd/files/cache.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ import (
1919
"github.com/coder/coder/v2/coderd/util/lazy"
2020
)
2121

22+
type FileAcquirer interface {
23+
Acquire(ctx context.Context, fileID uuid.UUID) (*CloseFS, error)
24+
}
25+
2226
// NewFromStore returns a file cache that will fetch files from the provided
2327
// database.
2428
func NewFromStore(store database.Store, registerer prometheus.Registerer, authz rbac.Authorizer) *Cache {

coderd/files/closer.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package files
2+
3+
import (
4+
"context"
5+
"sync"
6+
7+
"github.com/google/uuid"
8+
"golang.org/x/xerrors"
9+
)
10+
11+
// CacheCloser is a cache wrapper used to close all acquired files.
12+
// This is a more simple interface to use if opening multiple files at once.
13+
type CacheCloser struct {
14+
cache FileAcquirer
15+
16+
close []*CloseFS
17+
mu sync.Mutex
18+
closed bool
19+
}
20+
21+
func NewCacheCloser(cache FileAcquirer) *CacheCloser {
22+
return &CacheCloser{
23+
cache: cache,
24+
close: make([]*CloseFS, 0),
25+
}
26+
}
27+
28+
func (c *CacheCloser) Close() {
29+
c.mu.Lock()
30+
defer c.mu.Unlock()
31+
32+
for _, fs := range c.close {
33+
fs.Close()
34+
}
35+
c.closed = true
36+
}
37+
38+
func (c *CacheCloser) Acquire(ctx context.Context, fileID uuid.UUID) (*CloseFS, error) {
39+
c.mu.Lock()
40+
defer c.mu.Unlock()
41+
42+
if c.closed {
43+
return nil, xerrors.New("cache is closed, and cannot acquire new files")
44+
}
45+
46+
f, err := c.cache.Acquire(ctx, fileID)
47+
if err != nil {
48+
return nil, err
49+
}
50+
51+
c.close = append(c.close, f)
52+
53+
return f, nil
54+
}

0 commit comments

Comments
 (0)