github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/cmn/gco.go (about) 1 // Package cmn provides common constants, types, and utilities for AIS clients 2 // and AIStore. 3 /* 4 * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. 5 */ 6 package cmn 7 8 import ( 9 "sync" 10 ratomic "sync/atomic" 11 12 "github.com/NVIDIA/aistore/api/apc" 13 "github.com/NVIDIA/aistore/cmn/cos" 14 ) 15 16 // GCO (Global Config Owner) is responsible for updating and notifying 17 // listeners about any changes in the config. Global Config is loaded 18 // at startup and then can be accessed/updated by other services. 19 20 type ( 21 gco struct { 22 c ratomic.Pointer[Config] // (cluster + local + override config) 23 oc ratomic.Pointer[ConfigToSet] // for a node to override inherited (global) configuration 24 confPath ratomic.Pointer[string] // initial (plain-text) global config path 25 mtx sync.Mutex // [BeginUpdate -- CommitUpdate] 26 } 27 ) 28 29 var GCO *gco 30 31 func init() { 32 GCO = &gco{} 33 GCO.c.Store(&Config{}) 34 35 Rom.init() 36 } 37 38 ///////// 39 // gco // 40 ///////// 41 42 func (gco *gco) Get() *Config { return gco.c.Load() } 43 44 func (gco *gco) Put(config *Config) { 45 gco.c.Store(config) 46 // update assorted read-mostly knobs 47 Rom.Set(&config.ClusterConfig) 48 } 49 50 func (gco *gco) GetOverride() *ConfigToSet { return gco.oc.Load() } 51 func (gco *gco) PutOverride(config *ConfigToSet) { gco.oc.Store(config) } 52 53 func (gco *gco) MergeOverride(toUpdate *ConfigToSet) (overrideConfig *ConfigToSet) { 54 overrideConfig = gco.GetOverride() 55 if overrideConfig == nil { 56 overrideConfig = toUpdate 57 } else { 58 overrideConfig.Merge(toUpdate) 59 } 60 return 61 } 62 63 func (gco *gco) SetLocalFSPaths(toUpdate *ConfigToSet) (overrideConfig *ConfigToSet) { 64 overrideConfig = gco.GetOverride() 65 if overrideConfig == nil { 66 overrideConfig = toUpdate 67 } else { 68 overrideConfig.FSP = toUpdate.FSP // no merging required 69 } 70 return 71 } 72 73 // CopyStruct is a shallow copy, which is fine as FSPaths and BackendConf "exceptions" 74 // are taken care of separately. When cloning, beware: config is a large structure. 75 func (gco *gco) Clone() *Config { 76 config := &Config{} 77 cos.CopyStruct(config, gco.Get()) 78 return config 79 } 80 81 // When updating we need to make sure that the update is transaction and no 82 // other update can happen when other transaction is in progress. Therefore, 83 // we introduce locking mechanism which targets this problem. 84 // NOTE: 85 // - BeginUpdate must be followed by CommitUpdate. 86 // - `ais` package must use config-owner to modify config. 87 func (gco *gco) BeginUpdate() *Config { 88 gco.mtx.Lock() 89 return gco.Clone() 90 } 91 92 // CommitUpdate finalizes config update and notifies listeners. 93 // NOTE: `ais` package must use config-owner to modify config. 94 func (gco *gco) CommitUpdate(config *Config) { 95 gco.c.Store(config) 96 gco.mtx.Unlock() 97 } 98 99 // DiscardUpdate discards commit updates. 100 // NOTE: `ais` package must use config-owner to modify config 101 func (gco *gco) DiscardUpdate() { 102 gco.mtx.Unlock() 103 } 104 105 func (gco *gco) SetInitialGconfPath(path string) { gco.confPath.Store(&path) } 106 func (gco *gco) GetInitialGconfPath() string { return *gco.confPath.Load() } 107 108 func (gco *gco) Update(cluConfig *ClusterConfig) (err error) { 109 config := gco.Clone() 110 config.ClusterConfig = *cluConfig 111 override := gco.GetOverride() 112 if override != nil { 113 err = config.UpdateClusterConfig(override, apc.Daemon) // update and validate 114 } else { 115 err = config.Validate() 116 } 117 if err != nil { 118 return 119 } 120 gco.Put(config) 121 return 122 }