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  }