go-micro.dev/v5@v5.12.0/config/loader/memory/memory.go (about)

     1  package memory
     2  
     3  import (
     4  	"bytes"
     5  	"container/list"
     6  	"errors"
     7  	"fmt"
     8  	"strings"
     9  	"sync"
    10  	"sync/atomic"
    11  	"time"
    12  
    13  	"go-micro.dev/v5/config/loader"
    14  	"go-micro.dev/v5/config/reader"
    15  	"go-micro.dev/v5/config/reader/json"
    16  	"go-micro.dev/v5/config/source"
    17  )
    18  
    19  type memory struct {
    20  	// the current values
    21  	vals reader.Values
    22  	exit chan bool
    23  	// the current snapshot
    24  	snap *loader.Snapshot
    25  
    26  	watchers *list.List
    27  	opts     loader.Options
    28  
    29  	// all the sets
    30  	sets []*source.ChangeSet
    31  	// all the sources
    32  	sources []source.Source
    33  
    34  	sync.RWMutex
    35  }
    36  
    37  type updateValue struct {
    38  	value   reader.Value
    39  	version string
    40  }
    41  
    42  type watcher struct {
    43  	sync.Mutex
    44  	value   reader.Value
    45  	reader  reader.Reader
    46  	version atomic.Value
    47  	exit    chan bool
    48  	updates chan updateValue
    49  	path    []string
    50  }
    51  
    52  func (w *watcher) getVersion() string {
    53  	return w.version.Load().(string)
    54  }
    55  
    56  func (m *memory) watch(idx int, s source.Source) {
    57  	// watches a source for changes
    58  	watch := func(idx int, s source.Watcher) error {
    59  		for {
    60  			// get changeset
    61  			cs, err := s.Next()
    62  			if err != nil {
    63  				return err
    64  			}
    65  
    66  			m.Lock()
    67  
    68  			// save
    69  			m.sets[idx] = cs
    70  
    71  			// merge sets
    72  			set, err := m.opts.Reader.Merge(m.sets...)
    73  			if err != nil {
    74  				m.Unlock()
    75  				return err
    76  			}
    77  
    78  			// set values
    79  			m.vals, _ = m.opts.Reader.Values(set)
    80  			m.snap = &loader.Snapshot{
    81  				ChangeSet: set,
    82  				Version:   genVer(),
    83  			}
    84  			m.Unlock()
    85  
    86  			// send watch updates
    87  			m.update()
    88  		}
    89  	}
    90  
    91  	for {
    92  		// watch the source
    93  		w, err := s.Watch()
    94  		if err != nil {
    95  			time.Sleep(time.Second)
    96  			continue
    97  		}
    98  
    99  		done := make(chan bool)
   100  
   101  		// the stop watch func
   102  		go func() {
   103  			select {
   104  			case <-done:
   105  			case <-m.exit:
   106  			}
   107  			w.Stop()
   108  		}()
   109  
   110  		// block watch
   111  		if err := watch(idx, w); err != nil {
   112  			// do something better
   113  			time.Sleep(time.Second)
   114  		}
   115  
   116  		// close done chan
   117  		close(done)
   118  
   119  		// if the config is closed exit
   120  		select {
   121  		case <-m.exit:
   122  			return
   123  		default:
   124  		}
   125  	}
   126  }
   127  
   128  func (m *memory) loaded() bool {
   129  	var loaded bool
   130  	m.RLock()
   131  	if m.vals != nil {
   132  		loaded = true
   133  	}
   134  	m.RUnlock()
   135  	return loaded
   136  }
   137  
   138  // reload reads the sets and creates new values.
   139  func (m *memory) reload() error {
   140  	m.Lock()
   141  
   142  	// merge sets
   143  	set, err := m.opts.Reader.Merge(m.sets...)
   144  	if err != nil {
   145  		m.Unlock()
   146  		return err
   147  	}
   148  
   149  	// set values
   150  	if vals, err := m.opts.Reader.Values(set); err != nil {
   151  		m.vals = vals
   152  	}
   153  	m.snap = &loader.Snapshot{
   154  		ChangeSet: set,
   155  		Version:   genVer(),
   156  	}
   157  
   158  	m.Unlock()
   159  
   160  	// update watchers
   161  	m.update()
   162  
   163  	return nil
   164  }
   165  
   166  func (m *memory) update() {
   167  	m.RLock()
   168  
   169  	watchers := make([]*watcher, 0, m.watchers.Len())
   170  
   171  	for e := m.watchers.Front(); e != nil; e = e.Next() {
   172  		watchers = append(watchers, e.Value.(*watcher))
   173  	}
   174  
   175  	vals := m.vals
   176  	snap := m.snap
   177  	m.RUnlock()
   178  
   179  	for _, w := range watchers {
   180  		if w.getVersion() >= snap.Version {
   181  			continue
   182  		}
   183  
   184  		val, _ := vals.Get(w.path...)
   185  
   186  		m.RLock()
   187  		uv := updateValue{
   188  			version: m.snap.Version,
   189  			value:   val,
   190  		}
   191  		m.RUnlock()
   192  
   193  		select {
   194  		case w.updates <- uv:
   195  		default:
   196  		}
   197  	}
   198  }
   199  
   200  // Snapshot returns a snapshot of the current loaded config.
   201  func (m *memory) Snapshot() (*loader.Snapshot, error) {
   202  	if m.loaded() {
   203  		m.RLock()
   204  		snap := loader.Copy(m.snap)
   205  		m.RUnlock()
   206  		return snap, nil
   207  	}
   208  
   209  	// not loaded, sync
   210  	if err := m.Sync(); err != nil {
   211  		return nil, err
   212  	}
   213  
   214  	// make copy
   215  	m.RLock()
   216  	snap := loader.Copy(m.snap)
   217  	m.RUnlock()
   218  
   219  	return snap, nil
   220  }
   221  
   222  // Sync loads all the sources, calls the parser and updates the config.
   223  func (m *memory) Sync() error {
   224  	//nolint:prealloc
   225  	var sets []*source.ChangeSet
   226  
   227  	m.Lock()
   228  
   229  	// read the source
   230  	var gerr []string
   231  
   232  	for _, source := range m.sources {
   233  		ch, err := source.Read()
   234  		if err != nil {
   235  			gerr = append(gerr, err.Error())
   236  			continue
   237  		}
   238  		sets = append(sets, ch)
   239  	}
   240  
   241  	// merge sets
   242  	set, err := m.opts.Reader.Merge(sets...)
   243  	if err != nil {
   244  		m.Unlock()
   245  		return err
   246  	}
   247  
   248  	// set values
   249  	vals, err := m.opts.Reader.Values(set)
   250  	if err != nil {
   251  		m.Unlock()
   252  		return err
   253  	}
   254  	m.vals = vals
   255  	m.snap = &loader.Snapshot{
   256  		ChangeSet: set,
   257  		Version:   genVer(),
   258  	}
   259  
   260  	m.Unlock()
   261  
   262  	// update watchers
   263  	m.update()
   264  
   265  	if len(gerr) > 0 {
   266  		return fmt.Errorf("source loading errors: %s", strings.Join(gerr, "\n"))
   267  	}
   268  
   269  	return nil
   270  }
   271  
   272  func (m *memory) Close() error {
   273  	select {
   274  	case <-m.exit:
   275  		return nil
   276  	default:
   277  		close(m.exit)
   278  	}
   279  	return nil
   280  }
   281  
   282  func (m *memory) Get(path ...string) (reader.Value, error) {
   283  	if !m.loaded() {
   284  		if err := m.Sync(); err != nil {
   285  			return nil, err
   286  		}
   287  	}
   288  
   289  	m.Lock()
   290  	defer m.Unlock()
   291  
   292  	// did sync actually work?
   293  	if m.vals != nil {
   294  		return m.vals.Get(path...)
   295  	}
   296  
   297  	// assuming vals is nil
   298  	// create new vals
   299  
   300  	ch := m.snap.ChangeSet
   301  
   302  	// we are truly screwed, trying to load in a hacked way
   303  	v, err := m.opts.Reader.Values(ch)
   304  	if err != nil {
   305  		return nil, err
   306  	}
   307  
   308  	// lets set it just because
   309  	m.vals = v
   310  
   311  	if m.vals != nil {
   312  		return m.vals.Get(path...)
   313  	}
   314  
   315  	// ok we're going hardcore now
   316  
   317  	return nil, errors.New("no values")
   318  }
   319  
   320  func (m *memory) Load(sources ...source.Source) error {
   321  	var gerrors []string
   322  
   323  	for _, source := range sources {
   324  		set, err := source.Read()
   325  		if err != nil {
   326  			gerrors = append(gerrors,
   327  				fmt.Sprintf("error loading source %s: %v",
   328  					source,
   329  					err))
   330  			// continue processing
   331  			continue
   332  		}
   333  		m.Lock()
   334  		m.sources = append(m.sources, source)
   335  		m.sets = append(m.sets, set)
   336  		idx := len(m.sets) - 1
   337  		m.Unlock()
   338  		if !m.opts.WithWatcherDisabled {
   339  			go m.watch(idx, source)
   340  		}
   341  	}
   342  
   343  	if err := m.reload(); err != nil {
   344  		gerrors = append(gerrors, err.Error())
   345  	}
   346  
   347  	// Return errors
   348  	if len(gerrors) != 0 {
   349  		return errors.New(strings.Join(gerrors, "\n"))
   350  	}
   351  	return nil
   352  }
   353  
   354  func (m *memory) Watch(path ...string) (loader.Watcher, error) {
   355  	if m.opts.WithWatcherDisabled {
   356  		return nil, errors.New("watcher is disabled")
   357  	}
   358  
   359  	value, err := m.Get(path...)
   360  	if err != nil {
   361  		return nil, err
   362  	}
   363  
   364  	m.Lock()
   365  
   366  	w := &watcher{
   367  		exit:    make(chan bool),
   368  		path:    path,
   369  		value:   value,
   370  		reader:  m.opts.Reader,
   371  		updates: make(chan updateValue, 1),
   372  	}
   373  	w.version.Store(m.snap.Version)
   374  
   375  	e := m.watchers.PushBack(w)
   376  
   377  	m.Unlock()
   378  
   379  	go func() {
   380  		<-w.exit
   381  		m.Lock()
   382  		m.watchers.Remove(e)
   383  		m.Unlock()
   384  	}()
   385  
   386  	return w, nil
   387  }
   388  
   389  func (m *memory) String() string {
   390  	return "memory"
   391  }
   392  
   393  func (w *watcher) Next() (*loader.Snapshot, error) {
   394  	update := func(v reader.Value) *loader.Snapshot {
   395  		w.value = v
   396  
   397  		cs := &source.ChangeSet{
   398  			Data:      v.Bytes(),
   399  			Format:    w.reader.String(),
   400  			Source:    "memory",
   401  			Timestamp: time.Now(),
   402  		}
   403  		cs.Checksum = cs.Sum()
   404  
   405  		return &loader.Snapshot{
   406  			ChangeSet: cs,
   407  			Version:   w.getVersion(),
   408  		}
   409  	}
   410  
   411  	for {
   412  		select {
   413  		case <-w.exit:
   414  			return nil, errors.New("watcher stopped")
   415  
   416  		case uv := <-w.updates:
   417  			if uv.version <= w.getVersion() {
   418  				continue
   419  			}
   420  
   421  			v := uv.value
   422  
   423  			w.version.Store(uv.version)
   424  
   425  			if bytes.Equal(w.value.Bytes(), v.Bytes()) {
   426  				continue
   427  			}
   428  
   429  			return update(v), nil
   430  		}
   431  	}
   432  }
   433  
   434  func (w *watcher) Stop() error {
   435  	w.Lock()
   436  	defer w.Unlock()
   437  
   438  	select {
   439  	case <-w.exit:
   440  	default:
   441  		close(w.exit)
   442  		close(w.updates)
   443  	}
   444  
   445  	return nil
   446  }
   447  
   448  func genVer() string {
   449  	return fmt.Sprintf("%d", time.Now().UnixNano())
   450  }
   451  
   452  func NewLoader(opts ...loader.Option) loader.Loader {
   453  	options := loader.Options{
   454  		Reader: json.NewReader(),
   455  	}
   456  
   457  	for _, o := range opts {
   458  		o(&options)
   459  	}
   460  
   461  	m := &memory{
   462  		exit:     make(chan bool),
   463  		opts:     options,
   464  		watchers: list.New(),
   465  		sources:  options.Source,
   466  	}
   467  
   468  	m.sets = make([]*source.ChangeSet, len(options.Source))
   469  
   470  	for i, s := range options.Source {
   471  		m.sets[i] = &source.ChangeSet{Source: s.String()}
   472  		if !options.WithWatcherDisabled {
   473  			go m.watch(i, s)
   474  		}
   475  	}
   476  
   477  	return m
   478  }