github.com/braveheart12/just@v0.8.7/pulsar/statemachine.go (about)

     1  /*
     2   *    Copyright 2019 Insolar Technologies
     3   *
     4   *    Licensed under the Apache License, Version 2.0 (the "License");
     5   *    you may not use this file except in compliance with the License.
     6   *    You may obtain a copy of the License at
     7   *
     8   *        http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   *    Unless required by applicable law or agreed to in writing, software
    11   *    distributed under the License is distributed on an "AS IS" BASIS,
    12   *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   *    See the License for the specific language governing permissions and
    14   *    limitations under the License.
    15   */
    16  
    17  package pulsar
    18  
    19  import (
    20  	"context"
    21  	"sync"
    22  
    23  	"github.com/insolar/insolar/instrumentation/inslogger"
    24  	"github.com/insolar/insolar/instrumentation/instracer"
    25  )
    26  
    27  //go:generate stringer -type=State
    28  type State int
    29  
    30  const (
    31  	// Failed means that current iteration is broken
    32  	Failed State = iota
    33  
    34  	// WaitingForStart means that state machine is waiting for the start
    35  	WaitingForStart
    36  
    37  	// GenerateEntropy means that state machine is generating entropy for a current slot
    38  	GenerateEntropy
    39  
    40  	// WaitingForEntropySigns means that state machine is waiting for other pulsars' signs of entropy
    41  	WaitingForEntropySigns
    42  
    43  	// SendingEntropy means that state machine is sending entropy to other pulsars
    44  	SendingEntropy
    45  
    46  	// WaitingForEntropy means that state machine is waiting for the entropy for other pulsars
    47  	WaitingForEntropy
    48  
    49  	// SendingVector means that state machine is sending verctor to other pulsars
    50  	SendingVector
    51  
    52  	// WaitingForVectors means that state machine is waiting for other pulsars' vectors
    53  	WaitingForVectors
    54  
    55  	// Verifying means that state machine is verifying bft-table
    56  	Verifying
    57  
    58  	// SendingPulseSign means that state machine is sending sign to chosen pulsar
    59  	SendingPulseSign
    60  
    61  	// WaitingForPulseSigns means that state machine is waiting for signs to chosen pulsar
    62  	WaitingForPulseSigns
    63  
    64  	// SendingPulseSign means that state machine is sending pulse to network
    65  	SendingPulse
    66  )
    67  
    68  // StateSwitcher is a base for pulsar's state machine
    69  type StateSwitcher interface {
    70  	SwitchToState(ctx context.Context, state State, args interface{})
    71  	GetState() State
    72  	setState(state State)
    73  	SetPulsar(pulsar *Pulsar)
    74  }
    75  
    76  // StateSwitcherImpl is a base implementation of the pulsar's state machine
    77  type StateSwitcherImpl struct {
    78  	pulsar *Pulsar
    79  	state  State
    80  	lock   sync.RWMutex
    81  }
    82  
    83  func (switcher *StateSwitcherImpl) GetState() State {
    84  	switcher.lock.RLock()
    85  	defer switcher.lock.RUnlock()
    86  	return switcher.state
    87  }
    88  
    89  func (switcher *StateSwitcherImpl) setState(state State) {
    90  	switcher.lock.Lock()
    91  	defer switcher.lock.Unlock()
    92  	switcher.state = state
    93  }
    94  
    95  // SetPulsar sets pulsar of the current instance
    96  func (switcher *StateSwitcherImpl) SetPulsar(pulsar *Pulsar) {
    97  	switcher.setState(WaitingForStart)
    98  	switcher.pulsar = pulsar
    99  }
   100  
   101  // SwitchToState switches the state-machine to another step
   102  func (switcher *StateSwitcherImpl) SwitchToState(ctx context.Context, state State, args interface{}) {
   103  	ctx, span := instracer.StartSpan(ctx, "Pulsar.SwitchToState")
   104  	defer span.End()
   105  
   106  	logger := inslogger.FromContext(ctx)
   107  	logger.Debugf("Switch state from %v to %v, node - %v", switcher.GetState().String(), state.String(), switcher.pulsar.Config.MainListenerAddress)
   108  	if state < switcher.GetState() && (state != WaitingForStart && state != Failed) {
   109  		logger.Panic("Attempt to set a backward step. %v", switcher.pulsar.Config.MainListenerAddress)
   110  	}
   111  
   112  	logger.Debug(".setState(state)")
   113  	switcher.setState(state)
   114  
   115  	switch state {
   116  	case WaitingForStart:
   117  		logger.Debug("switcher.pulsar.clearState()")
   118  		switcher.pulsar.clearState()
   119  	case WaitingForEntropySigns:
   120  		switcher.pulsar.waitForEntropySigns(ctx)
   121  	case SendingEntropy:
   122  		switcher.pulsar.sendEntropy(ctx)
   123  	case WaitingForEntropy:
   124  		switcher.pulsar.waitForEntropy(ctx)
   125  	case SendingVector:
   126  		switcher.pulsar.sendVector(ctx)
   127  	case WaitingForVectors:
   128  		switcher.pulsar.waitForVectors(ctx)
   129  	case Verifying:
   130  		switcher.pulsar.verify(ctx)
   131  	case WaitingForPulseSigns:
   132  		switcher.pulsar.waitForPulseSigns(ctx)
   133  	case SendingPulseSign:
   134  		switcher.pulsar.sendPulseSign(ctx)
   135  	case SendingPulse:
   136  		switcher.pulsar.sendPulseToNodesAndPulsars(ctx)
   137  	case Failed:
   138  		switcher.pulsar.handleErrorState(ctx, args.(error))
   139  		switcher.setState(WaitingForStart)
   140  	}
   141  }