code.vegaprotocol.io/vega@v0.79.0/core/snapshot/worker.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package snapshot
    17  
    18  import (
    19  	"encoding/hex"
    20  	"sync/atomic"
    21  	"time"
    22  
    23  	"code.vegaprotocol.io/vega/core/types"
    24  	"code.vegaprotocol.io/vega/libs/crypto"
    25  	"code.vegaprotocol.io/vega/logging"
    26  )
    27  
    28  type treeKeyToSnapshot struct {
    29  	treeKey   []byte
    30  	namespace types.SnapshotNamespace
    31  }
    32  
    33  type snapshotResult struct {
    34  	input    treeKeyToSnapshot
    35  	toRemove bool
    36  	err      error
    37  	state    []byte
    38  	updated  bool
    39  }
    40  
    41  func gatherState(e *Engine, treeKeysToSnapshotChan chan treeKeyToSnapshot, snapshotResultsChan chan<- snapshotResult, treeKeysCounter *atomic.Int64, recordMetrics *snapMetricsState) {
    42  	for toSnapshot := range treeKeysToSnapshotChan {
    43  		// this is for metrics
    44  		startTime := time.Now()
    45  		currentNamespace := toSnapshot.namespace
    46  
    47  		treeKeyStr := string(toSnapshot.treeKey)
    48  
    49  		t0 := time.Now()
    50  
    51  		e.snapshotLock.RLock()
    52  		provider := e.treeKeysToProviders[treeKeyStr]
    53  		providerKey := e.treeKeysToProviderKeys[treeKeyStr]
    54  		e.snapshotLock.RUnlock()
    55  
    56  		if provider.Stopped() {
    57  			snapshotResultsChan <- snapshotResult{input: toSnapshot, updated: true, toRemove: true}
    58  			if treeKeysCounter.Add(-1) <= 0 {
    59  				close(treeKeysToSnapshotChan)
    60  				close(snapshotResultsChan)
    61  			}
    62  			continue
    63  		}
    64  
    65  		state, additionalProviders, err := provider.GetState(providerKey)
    66  		if err != nil {
    67  			snapshotResultsChan <- snapshotResult{input: toSnapshot, err: err, updated: true}
    68  			close(treeKeysToSnapshotChan)
    69  			close(snapshotResultsChan)
    70  			return
    71  		}
    72  
    73  		var treeKeys [][]byte
    74  		var ok bool
    75  		additionalTreeKeysToSnapshot := []treeKeyToSnapshot{}
    76  
    77  		// The provider has generated new providers, register them with the engine
    78  		// add them to the AVL tree
    79  		for _, additionalProvider := range additionalProviders {
    80  			knownTreeKeys := map[string]struct{}{}
    81  			// need to atomically check what's in there for the tree key and then add the provider
    82  			e.snapshotLock.Lock()
    83  			treeKeys, ok = e.namespacesToTreeKeys[additionalProvider.Namespace()]
    84  			if ok {
    85  				for _, treeKey := range treeKeys {
    86  					knownTreeKeys[string(treeKey)] = struct{}{}
    87  				}
    88  			}
    89  			e.addProviders(additionalProvider)
    90  			e.snapshotLock.Unlock()
    91  			e.log.Debug("Additional provider added by the worker",
    92  				logging.String("namespace", additionalProvider.Namespace().String()),
    93  			)
    94  
    95  			e.snapshotLock.RLock()
    96  			treeKeys, ok = e.namespacesToTreeKeys[additionalProvider.Namespace()]
    97  			e.snapshotLock.RUnlock()
    98  			if !ok || len(treeKeys) == 0 {
    99  				continue
   100  			}
   101  
   102  			for _, tk := range treeKeys {
   103  				// ignore tree keys we've already done
   104  				if _, ok := knownTreeKeys[string(tk)]; ok {
   105  					continue
   106  				}
   107  				additionalTreeKeysToSnapshot = append(additionalTreeKeysToSnapshot, treeKeyToSnapshot{treeKey: tk, namespace: additionalProvider.Namespace()})
   108  			}
   109  		}
   110  
   111  		e.log.Debug("State updated",
   112  			logging.String("tree-key", treeKeyStr),
   113  			logging.String("hash", hex.EncodeToString(crypto.Hash(state))),
   114  			logging.Float64("took", time.Since(t0).Seconds()),
   115  		)
   116  
   117  		treeKeysCounter.Add(int64(len(additionalTreeKeysToSnapshot)))
   118  
   119  		for _, treeKeyToSnapshot := range additionalTreeKeysToSnapshot {
   120  			treeKeysToSnapshotChan <- treeKeyToSnapshot
   121  		}
   122  
   123  		snapshotResultsChan <- snapshotResult{input: toSnapshot, state: state, updated: true}
   124  
   125  		if treeKeysCounter.Add(-1) <= 0 {
   126  			close(treeKeysToSnapshotChan)
   127  			close(snapshotResultsChan)
   128  		}
   129  
   130  		timeTaken := time.Since(startTime)
   131  		recordMetrics.Register(currentNamespace.String(), timeTaken, len(state))
   132  	}
   133  }