Thanks to visit codestin.com
Credit goes to github.com

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)