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 }