github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/ais/gconfig.go (about) 1 // Package ais provides core functionality for the AIStore object storage. 2 /* 3 * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 4 */ 5 package ais 6 7 import ( 8 "net/http" 9 "net/url" 10 "os" 11 "path/filepath" 12 "sync" 13 "time" 14 15 "github.com/NVIDIA/aistore/api/apc" 16 "github.com/NVIDIA/aistore/cmn" 17 "github.com/NVIDIA/aistore/cmn/cos" 18 "github.com/NVIDIA/aistore/cmn/debug" 19 "github.com/NVIDIA/aistore/cmn/fname" 20 "github.com/NVIDIA/aistore/cmn/jsp" 21 "github.com/NVIDIA/aistore/cmn/nlog" 22 "github.com/NVIDIA/aistore/memsys" 23 ) 24 25 type ( 26 globalConfig struct { 27 _sgl *memsys.SGL 28 cmn.ClusterConfig 29 } 30 configOwner struct { 31 globalFpath string 32 immSize int64 33 sync.Mutex 34 } 35 36 configModifier struct { 37 pre func(ctx *configModifier, clone *globalConfig) (updated bool, err error) 38 final func(ctx *configModifier, clone *globalConfig) 39 40 oldConfig *cmn.Config 41 toUpdate *cmn.ConfigToSet 42 msg *apc.ActMsg 43 query url.Values 44 hdr http.Header 45 wait bool 46 } 47 ) 48 49 // interface guard 50 var _ revs = (*globalConfig)(nil) 51 52 // as revs 53 func (*globalConfig) tag() string { return revsConfTag } 54 func (config *globalConfig) version() int64 { return config.Version } 55 func (*globalConfig) jit(p *proxy) revs { g, _ := p.owner.config.get(); return g } 56 57 func (config *globalConfig) sgl() *memsys.SGL { 58 if config._sgl.IsNil() { 59 return nil 60 } 61 return config._sgl 62 } 63 64 func (config *globalConfig) marshal() []byte { 65 config._sgl = config._encode(0) 66 return config._sgl.Bytes() 67 } 68 69 func (config *globalConfig) _encode(immSize int64) (sgl *memsys.SGL) { 70 sgl = memsys.PageMM().NewSGL(immSize) 71 err := jsp.Encode(sgl, config, config.JspOpts()) 72 debug.AssertNoErr(err) 73 return 74 } 75 76 ///////////////// 77 // configOwner // 78 ///////////////// 79 80 func newConfigOwner(config *cmn.Config) (co *configOwner) { 81 co = &configOwner{} 82 co.globalFpath = filepath.Join(config.ConfigDir, fname.GlobalConfig) 83 return 84 } 85 86 // NOTE: 87 // iff user ever executed transient config updates this loaded 88 // from disk version will differ from in-memory cmn.GCO.Get() 89 // (with respect to those in-memory only updated values) 90 // See also: 91 // - api.SetClusterConfig 92 // - apc.ActTransient 93 func (co *configOwner) get() (clone *globalConfig, err error) { 94 clone = &globalConfig{} 95 if _, err = jsp.LoadMeta(co.globalFpath, clone); err == nil { 96 return clone, nil 97 } 98 if os.IsNotExist(err) { 99 err = nil 100 } else { 101 nlog.Errorf("failed to load global config from %s: %v", co.globalFpath, err) 102 } 103 return nil, err 104 } 105 106 func (*configOwner) version() int64 { return cmn.GCO.Get().Version } 107 108 // is called under co.lock 109 func (co *configOwner) _runPre(ctx *configModifier) (clone *globalConfig, err error) { 110 clone, err = co.get() 111 if err != nil { 112 return 113 } 114 if clone == nil { 115 // missing config - try to load initial plain-text 116 clone = &globalConfig{} 117 _, err = jsp.Load(cmn.GCO.GetInitialGconfPath(), clone, jsp.Plain()) // must exist 118 if err != nil { 119 return clone, err 120 } 121 } 122 123 var updated bool 124 if updated, err = ctx.pre(ctx, clone); err != nil || !updated { 125 return nil, err 126 } 127 128 ctx.oldConfig = cmn.GCO.Get() 129 if err = cmn.GCO.Update(&clone.ClusterConfig); err != nil { 130 return nil, err 131 } 132 133 clone.Version++ 134 clone.LastUpdated = time.Now().String() 135 clone._sgl = clone._encode(co.immSize) 136 co.immSize = max(co.immSize, clone._sgl.Len()) 137 if err = co.persist(clone, nil); err != nil { 138 clone._sgl.Free() 139 clone._sgl = nil 140 return nil, cmn.NewErrFailedTo(nil, "persist", clone, err) 141 } 142 return clone, nil 143 } 144 145 // Update the global config on primary proxy. 146 func (co *configOwner) modify(ctx *configModifier) (config *globalConfig, err error) { 147 co.Lock() 148 config, err = co._runPre(ctx) 149 co.Unlock() 150 if err != nil || config == nil { 151 return config, err 152 } 153 if ctx.final != nil { 154 ctx.final(ctx, config) 155 } 156 return config, nil 157 } 158 159 func (co *configOwner) persist(clone *globalConfig, payload msPayload) error { 160 if co.persistBytes(payload, co.globalFpath) { 161 return nil 162 } 163 164 sgl := clone._sgl 165 if sgl == nil { 166 sgl = clone._encode(co.immSize) 167 co.immSize = max(co.immSize, sgl.Len()) 168 defer sgl.Free() 169 } 170 return jsp.SaveMeta(co.globalFpath, clone, sgl) 171 } 172 173 func (*configOwner) persistBytes(payload msPayload, globalFpath string) (done bool) { 174 if payload == nil { 175 return 176 } 177 confValue := payload[revsConfTag] 178 if confValue == nil { 179 return 180 } 181 var ( 182 config globalConfig 183 wto = cos.NewBuffer(confValue) 184 ) 185 err := jsp.SaveMeta(globalFpath, &config, wto) 186 done = err == nil 187 return 188 } 189 190 // NOTE: must be called under config-owner lock 191 func setConfig(toUpdate *cmn.ConfigToSet, transient bool) (err error) { 192 clone := cmn.GCO.Clone() 193 err = setConfigInMem(toUpdate, clone, apc.Daemon) 194 if err != nil { 195 return err 196 } 197 override := cmn.GCO.GetOverride() 198 if override == nil { 199 override = toUpdate 200 } else { 201 override.Merge(toUpdate) 202 } 203 if !transient { 204 if err = cmn.SaveOverrideConfig(clone.ConfigDir, override); err != nil { 205 return err 206 } 207 } 208 209 cmn.GCO.Put(clone) 210 cmn.GCO.PutOverride(override) 211 return nil 212 } 213 214 func setConfigInMem(toUpdate *cmn.ConfigToSet, config *cmn.Config, asType string) (err error) { 215 err = config.UpdateClusterConfig(toUpdate, asType) 216 return 217 } 218 219 func (co *configOwner) resetDaemonConfig() (err error) { 220 co.Lock() 221 oldConfig := cmn.GCO.Get() 222 config, err := co.get() 223 if err != nil || config == nil { 224 co.Unlock() 225 nlog.Infof("Warning: reset config %s: %v", oldConfig, err) 226 return err 227 } 228 cmn.GCO.PutOverride(nil) 229 err = cos.RemoveFile(filepath.Join(oldConfig.ConfigDir, fname.OverrideConfig)) 230 if err != nil { 231 co.Unlock() 232 return 233 } 234 cmn.GCO.Update(&config.ClusterConfig) 235 co.Unlock() 236 return 237 }