fix: close modsdir snapshot files after writing

This commit is contained in:
Taylor 2026-03-24 11:12:03 -07:00
parent 6bb0218388
commit 8722a3f567
2 changed files with 78 additions and 1 deletions

View file

@ -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)
}

View 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
}