Skip to content

Commit 556b095

Browse files
authored
chore: add cacheCloser to cleanup all opened files (#18473)
1 parent 9b5d499 commit 556b095

File tree

3 files changed

+79
-16
lines changed

3 files changed

+79
-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: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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+
closers []func()
17+
mu sync.Mutex
18+
}
19+
20+
func NewCacheCloser(cache FileAcquirer) *CacheCloser {
21+
return &CacheCloser{
22+
cache: cache,
23+
closers: make([]func(), 0),
24+
}
25+
}
26+
27+
func (c *CacheCloser) Close() {
28+
c.mu.Lock()
29+
defer c.mu.Unlock()
30+
31+
for _, doClose := range c.closers {
32+
doClose()
33+
}
34+
35+
// Prevent further acquisitions
36+
c.cache = nil
37+
// Remove any references
38+
c.closers = nil
39+
}
40+
41+
func (c *CacheCloser) Acquire(ctx context.Context, fileID uuid.UUID) (*CloseFS, error) {
42+
c.mu.Lock()
43+
defer c.mu.Unlock()
44+
45+
if c.cache == nil {
46+
return nil, xerrors.New("cache is closed, and cannot acquire new files")
47+
}
48+
49+
f, err := c.cache.Acquire(ctx, fileID)
50+
if err != nil {
51+
return nil, err
52+
}
53+
54+
c.closers = append(c.closers, f.close)
55+
56+
return f, nil
57+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy