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 }