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

     1  // Package volume provides volume (a.k.a. pool of disks) abstraction and methods to configure, store,
     2  // and validate the corresponding metadata. AIS volume is built on top of mountpaths (fs package).
     3  /*
     4   * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved.
     5   */
     6  package volume
     7  
     8  import (
     9  	"fmt"
    10  	"path/filepath"
    11  
    12  	"github.com/NVIDIA/aistore/cmn"
    13  	"github.com/NVIDIA/aistore/cmn/cos"
    14  	"github.com/NVIDIA/aistore/cmn/debug"
    15  	"github.com/NVIDIA/aistore/cmn/fname"
    16  	"github.com/NVIDIA/aistore/cmn/jsp"
    17  	"github.com/NVIDIA/aistore/cmn/nlog"
    18  	"github.com/NVIDIA/aistore/fs"
    19  	"github.com/NVIDIA/aistore/ios"
    20  )
    21  
    22  const vmdCopies = 3
    23  
    24  type (
    25  	fsMpathMD struct {
    26  		Ext     any       `json:"ext,omitempty"` // reserved for within-metaversion extensions
    27  		Path    string    `json:"mountpath"`
    28  		Label   ios.Label `json:"mountpath_label"`
    29  		Fs      string    `json:"fs"`
    30  		FsType  string    `json:"fs_type"`
    31  		FsID    cos.FsID  `json:"fs_id"`
    32  		Enabled bool      `json:"enabled"`
    33  	}
    34  
    35  	// VMD is AIS target's volume metadata structure
    36  	VMD struct {
    37  		Mountpaths map[string]*fsMpathMD `json:"mountpaths"` // mountpath => details
    38  		cksum      *cos.Cksum            // content checksum
    39  		DaemonID   string                `json:"daemon_id"` // this target node ID
    40  		info       string                // String() only once
    41  		Version    uint64                `json:"version,string"` // version inc-s upon mountpath add/remove, etc.
    42  	}
    43  )
    44  
    45  func _mpathGreaterEq(curr, prev *VMD, mpath string) bool {
    46  	currMd, currOk := curr.Mountpaths[mpath]
    47  	prevMd, prevOk := prev.Mountpaths[mpath]
    48  	if !currOk {
    49  		return false
    50  	} else if !prevOk {
    51  		return true
    52  	} else if currMd.Enabled {
    53  		return true
    54  	} else if currMd.Enabled == prevMd.Enabled {
    55  		return true
    56  	}
    57  	return false
    58  }
    59  
    60  /////////
    61  // VMD //
    62  /////////
    63  
    64  // interface guard
    65  var _ jsp.Opts = (*VMD)(nil)
    66  
    67  func (*VMD) JspOpts() jsp.Options {
    68  	opts := jsp.CCSign(cmn.MetaverVMD)
    69  	opts.OldMetaverOk = 1
    70  	return opts
    71  }
    72  
    73  func (vmd *VMD) addMountpath(mi *fs.Mountpath, enabled bool) {
    74  	vmd.Mountpaths[mi.Path] = &fsMpathMD{
    75  		Path:    mi.Path,
    76  		Label:   mi.Label,
    77  		Fs:      mi.Fs,
    78  		FsType:  mi.FsType,
    79  		FsID:    mi.FsID,
    80  		Enabled: enabled,
    81  	}
    82  }
    83  
    84  func (vmd *VMD) load(mpath string) (err error) {
    85  	fpath := filepath.Join(mpath, fname.Vmd)
    86  	if vmd.cksum, err = jsp.LoadMeta(fpath, vmd); err != nil {
    87  		return
    88  	}
    89  	if vmd.DaemonID == "" {
    90  		debug.Assert(false) // cannot happen
    91  		err = fmt.Errorf("target ID is empty for vmd on %q", mpath)
    92  	}
    93  	return
    94  }
    95  
    96  func (vmd *VMD) persist() (err error) {
    97  	cnt, availCnt := fs.PersistOnMpaths(fname.Vmd, "", vmd, vmdCopies, nil, nil /*wto*/)
    98  	if cnt > 0 {
    99  		return
   100  	}
   101  	if availCnt == 0 {
   102  		nlog.Errorf("cannot store VMD: %v", cmn.ErrNoMountpaths)
   103  		return
   104  	}
   105  	return fmt.Errorf("failed to store VMD on any of the mountpaths (%d)", availCnt)
   106  }
   107  
   108  func (vmd *VMD) equal(other *VMD) bool {
   109  	debug.Assert(vmd.cksum != nil)
   110  	debug.Assert(other.cksum != nil)
   111  	return vmd.DaemonID == other.DaemonID &&
   112  		vmd.Version == other.Version &&
   113  		vmd.cksum.Equal(other.cksum)
   114  }
   115  
   116  func (vmd *VMD) String() string {
   117  	if vmd.info != "" {
   118  		return vmd.info
   119  	}
   120  	return vmd._string()
   121  }
   122  
   123  func (vmd *VMD) _string() string {
   124  	mps := make([]string, len(vmd.Mountpaths))
   125  	i := 0
   126  	for mpath, md := range vmd.Mountpaths {
   127  		mps[i] = mpath
   128  		if !md.Enabled {
   129  			mps[i] += "(-)"
   130  		}
   131  		i++
   132  	}
   133  	return fmt.Sprintf("VMD v%d(%s, %v)", vmd.Version, vmd.DaemonID, mps)
   134  }