internal/disk_stats/disk_stats.go (93 lines of code) (raw):
package disk_stats //nolint:staticcheck
import (
"log/slog"
"os"
"path/filepath"
"golang.org/x/sys/unix"
)
type DiskStats struct {
All uint64 `json:"all"`
Free uint64 `json:"free"`
Indexed int64 `json:"indexed"`
Used uint64 `json:"used"`
}
type RepoStats struct {
IndexFileCount uint16 `json:"index_file_count"`
SizeInBytes uint64 `json:"size_in_bytes"`
}
func (r RepoStats) ToMap() map[string]interface{} {
return map[string]interface{}{
"index_file_count": r.IndexFileCount,
"size_in_bytes": r.SizeInBytes,
}
}
func DiskUsage(path string) (DiskStats, error) {
fs := unix.Statfs_t{}
err := unix.Statfs(path, &fs)
if err != nil {
return DiskStats{}, err
}
all := fs.Blocks * uint64(fs.Bsize) //nolint:gosec
free := fs.Bfree * uint64(fs.Bsize) //nolint:gosec
used := all - free
indexed, err := getIndexSize(path)
if indexed < 0 || err != nil {
slog.Error("can not get the index size", "path", path, "error", err)
indexed = -1
}
diskStats := DiskStats{
All: all,
Free: free,
Indexed: indexed,
Used: used,
}
return diskStats, nil
}
func GetIndexFiles(indexDir string, globs ...string) ([]string, error) {
var files []string
for _, g := range globs {
path := filepath.Join(indexDir, g)
f, err := filepath.Glob(path)
if err != nil {
return nil, err
}
files = append(files, f...)
}
return files, nil
}
func GetFileSizeAndCount(indexDir string, globs ...string) RepoStats {
files, err := GetIndexFiles(indexDir, globs...)
repoStats := RepoStats{}
if err != nil {
return repoStats
}
var sizeInBytes uint64
numFiles := len(files)
for i := 0; i < numFiles; i++ {
fileInfo, err := os.Stat(files[i])
if err != nil {
return repoStats
}
sizeInBytes += uint64(fileInfo.Size()) //nolint:gosec
}
repoStats.IndexFileCount = uint16(numFiles) //nolint:gosec
repoStats.SizeInBytes = sizeInBytes
return repoStats
}
func getIndexSize(path string) (int64, error) {
var size int64
err := filepath.WalkDir(path, func(_ string, d os.DirEntry, err error) error {
if err != nil {
return err
}
if !d.IsDir() {
info, err := d.Info()
if err != nil {
return err
}
size += int64(info.Size())
}
return nil
})
return size, err
}