mirror of
https://github.com/hashicorp/terraform.git
synced 2026-05-28 04:03:27 -04:00
fix: close modsdir snapshot files after writing
This commit is contained in:
parent
6bb0218388
commit
8722a3f567
2 changed files with 78 additions and 1 deletions
|
|
@ -5,6 +5,7 @@ package modsdir
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
|
@ -172,12 +173,15 @@ func (m Manifest) WriteSnapshot(w io.Writer) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func (m Manifest) WriteSnapshotToDir(dir string) error {
|
||||
func (m Manifest) WriteSnapshotToDir(dir string) (retErr error) {
|
||||
fn := filepath.Join(dir, ManifestSnapshotFilename)
|
||||
log.Printf("[TRACE] modsdir: writing modules manifest to %s", fn)
|
||||
w, err := os.Create(fn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
retErr = errors.Join(retErr, w.Close())
|
||||
}()
|
||||
return m.WriteSnapshot(w)
|
||||
}
|
||||
|
|
|
|||
73
internal/modsdir/manifest_test.go
Normal file
73
internal/modsdir/manifest_test.go
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
//go:build darwin || linux
|
||||
|
||||
// Copyright IBM Corp. 2014, 2026
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package modsdir
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime/debug"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func TestManifestWriteSnapshotToDirClosesFile(t *testing.T) {
|
||||
oldGCPercent := debug.SetGCPercent(-1)
|
||||
defer debug.SetGCPercent(oldGCPercent)
|
||||
|
||||
manifest := Manifest{
|
||||
"root": {
|
||||
Key: "root",
|
||||
Dir: "modules/root",
|
||||
},
|
||||
}
|
||||
|
||||
baseDir := t.TempDir()
|
||||
before := countOpenFileDescriptors(t)
|
||||
|
||||
const iterations = 32
|
||||
for i := range iterations {
|
||||
dir := filepath.Join(baseDir, fmt.Sprintf("manifest-%d", i))
|
||||
if err := os.Mkdir(dir, 0o755); err != nil {
|
||||
t.Fatalf("creating manifest dir %d: %s", i, err)
|
||||
}
|
||||
|
||||
if err := manifest.WriteSnapshotToDir(dir); err != nil {
|
||||
t.Fatalf("writing manifest %d: %s", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
after := countOpenFileDescriptors(t)
|
||||
if leaked := after - before; leaked > 2 {
|
||||
t.Fatalf("expected WriteSnapshotToDir to close its file descriptor, but open descriptor count increased by %d", leaked)
|
||||
}
|
||||
}
|
||||
|
||||
func countOpenFileDescriptors(t *testing.T) int {
|
||||
t.Helper()
|
||||
|
||||
var limit unix.Rlimit
|
||||
if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &limit); err != nil {
|
||||
t.Fatalf("reading RLIMIT_NOFILE: %s", err)
|
||||
}
|
||||
|
||||
maxFD := int(limit.Cur)
|
||||
if maxFD > 4096 {
|
||||
maxFD = 4096
|
||||
}
|
||||
|
||||
openDescriptors := 0
|
||||
for fd := range maxFD {
|
||||
if _, err := unix.FcntlInt(uintptr(fd), unix.F_GETFD, 0); err == nil {
|
||||
openDescriptors++
|
||||
} else if err != unix.EBADF {
|
||||
t.Fatalf("checking file descriptor %d: %s", fd, err)
|
||||
}
|
||||
}
|
||||
|
||||
return openDescriptors
|
||||
}
|
||||
Loading…
Reference in a new issue