Answer the question
In order to leave comments, you need to log in
Will there be race and data corruption in memory?
I store the configuration in one json file, plus the configuration must be thread-safe without smearing mutexes throughout the code (in my experience, finding a missing mutex is still suffering) and unnecessary copying.
As a result, I received a similar API:
cfg := config.Read()
defer cfg.Close()
ctx, cancel := context.WithTimeout(context.Background(), cfg.HTTP.Timeout.StopServer*time.Second)
package config
import (
"encoding/json"
"os"
"sync"
)
var (
configPool sync.Pool
cfgSync = &sync.RWMutex{}
cfgValue *Cfg
)
func Read() *Cfg {
var c *Cfg
if v := configPool.Get(); v != nil { //если в пуле есть "свободные" указатели то возвращаем их
return v.(*Cfg)
} else { //пул пуст, создаем новый указатель
c = newCfg()
valid(c)
configPool.Put(c)
return Read()
}
}
func (cfg *Cfg) Close() {
configPool.Put(cfg)
}
func newCfg() *Cfg {
cfgSync.RLock()
is := cfgValue == nil
cfgSync.RUnlock()
if is { //файл незагружен в память, загружаем
f, err := os.Open("./config/config.json")
if err != nil {
panic("Error open config file: `./config/config.json `" + err.Error())
}
defer f.Close()
dec := json.NewDecoder(f)
cfg := &Cfg{}
if err := dec.Decode(cfg); err != nil {
panic("Error parse config file: " + err.Error())
}
cfgSync.Lock()
cfgValue = cfg
cfgSync.Unlock()
}
//создаем новый указатель
ret := new(Cfg)
//копируем из старого в новый указатель
cfgSync.RLock()
*ret = *cfgValue
cfgSync.RUnlock()
//возвращаем копию
return ret
}
Answer the question
In order to leave comments, you need to log in
I think you're overcomplicating unnecessarily. If the values from the config are only readable, then thread safety is not needed. If you also expect a change, then pointers to "corrupted" objects are returned to the pool, which is also wrong.
If possible, it is better to read the config at the beginning of the execution, and also panic at the main level.
As a result, the code is simpler, and there is nothing to slow down:
package config
import (
"encoding/json"
"fmt"
"os"
)
type Cfg struct {
// Fields
}
var (
cfg *Cfg
)
func Config() *Cfg {
return cfg
}
func LoadConfig() error {
f, err := os.Open("./config/config.json")
if err != nil {
return fmt.Errorf("can't open config file: %w", err)
}
defer f.Close()
dec := json.NewDecoder(f)
var c *Cfg
if err := dec.Decode(c); err != nil {
return fmt.Errorf("can't decode config file: %w", err)
}
if err := validate(c); err != nil {
return fmt.Errorf("can't validate config file: %w", err)
}
cfg = c
return nil
}
func validate(cfg *Cfg) error {
// Logic
return nil
}
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question