github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/fs/utils.go (about)

     1  // Package fs provides mountpath and FQN abstractions and methods to resolve/map stored content
     2  /*
     3   * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved.
     4   */
     5  package fs
     6  
     7  import (
     8  	"fmt"
     9  	"io"
    10  	"os"
    11  	"path/filepath"
    12  	"strconv"
    13  
    14  	"github.com/NVIDIA/aistore/cmn/cos"
    15  )
    16  
    17  const maxNumCopies = 16
    18  
    19  var (
    20  	pid  int64 = 0xDEADBEEF   // pid of the current process
    21  	spid       = "0xDEADBEEF" // string version of the pid
    22  )
    23  
    24  func init() {
    25  	pid = int64(os.Getpid())
    26  	spid = strconv.FormatInt(pid, 16)
    27  
    28  	CSM = &contentSpecMgr{m: make(map[string]ContentResolver, 8)}
    29  }
    30  
    31  func IsDirEmpty(dir string) (names []string, empty bool, err error) {
    32  	var f *os.File
    33  	f, err = os.Open(dir)
    34  	if err != nil {
    35  		return nil, false, err
    36  	}
    37  	defer cos.Close(f)
    38  
    39  	// Try listing small number of files/dirs to do a quick emptiness check.
    40  	// If seems empty try a bigger sample to determine if it actually is.
    41  	for _, limit := range []int{10, 100, 1000, -1} {
    42  		names, err = f.Readdirnames(limit)
    43  		if err == io.EOF {
    44  			return nil, true, nil
    45  		}
    46  		if err != nil || len(names) == 0 {
    47  			return nil, true, err
    48  		}
    49  		// Firstly, check if there is any file at this level.
    50  		dirs := names[:0]
    51  		for _, sub := range names {
    52  			subDir := filepath.Join(dir, sub)
    53  			if finfo, erc := os.Stat(subDir); erc == nil {
    54  				if !finfo.IsDir() {
    55  					return names[:min(8, len(names))], false, nil
    56  				}
    57  				dirs = append(dirs, subDir)
    58  			}
    59  		}
    60  		// If not, then try to recurse into each directory.
    61  		for _, subDir := range dirs {
    62  			if nestedNames, empty, err := IsDirEmpty(subDir); err != nil {
    63  				return nil, false, err
    64  			} else if !empty {
    65  				return nestedNames, false, nil
    66  			}
    67  		}
    68  		// If we've just listed all the files/dirs then exit.
    69  		if len(names) < limit {
    70  			break
    71  		}
    72  	}
    73  	return nil, true, nil
    74  }
    75  
    76  func ValidateNCopies(tname string, copies int) (err error) {
    77  	if copies < 1 || copies > maxNumCopies {
    78  		return fmt.Errorf("%s: invalid num copies %d, must be in [1, %d] range",
    79  			tname, copies, maxNumCopies)
    80  	}
    81  	avail := GetAvail()
    82  	if num := len(avail); num < copies {
    83  		return fmt.Errorf("%s: number of copies (%d) exceeds the number of mountpaths (%d)",
    84  			tname, copies, num)
    85  	}
    86  	return nil
    87  }