github.com/asynkron/protoactor-go@v0.0.0-20240308120642-ef91a6abee75/cluster/consensus_checks.go (about)

     1  // Copyright (C) 2015-2022 Asynkron AB All rights reserved
     2  
     3  package cluster
     4  
     5  type GossipUpdater func(*GossipState, map[string]empty)
     6  
     7  // data structure helpful to store consensus check information and behavior.
     8  type ConsensusCheck struct {
     9  	affectedKeys []string
    10  	check        GossipUpdater
    11  }
    12  
    13  // creates a new ConsensusCheck value with the given data and return it back.
    14  func NewConsensusCheck(affectedKeys []string, check GossipUpdater) ConsensusCheck {
    15  	consensusCheck := ConsensusCheck{
    16  		affectedKeys: affectedKeys,
    17  		check:        check,
    18  	}
    19  
    20  	return consensusCheck
    21  }
    22  
    23  // acts as a storage of pointers to ConsensusCheck stored by key.
    24  type ConsensusChecks struct {
    25  	checks                 map[string]*ConsensusCheck
    26  	affectedKeysByStateKey map[string]map[string]empty
    27  }
    28  
    29  // creates a new ConsensusChecks value and returns a pointer to it.
    30  func NewConsensusChecks() *ConsensusChecks {
    31  	checks := ConsensusChecks{
    32  		checks:                 make(map[string]*ConsensusCheck),
    33  		affectedKeysByStateKey: make(map[string]map[string]empty),
    34  	}
    35  
    36  	return &checks
    37  }
    38  
    39  // iterates over all the keys stored in the set (map[string]empty) found in
    40  // the given key map and populates a slice of pointers to ConsensusCheck values
    41  // that is returned as a set of ConsensusCheck updated by the given key.
    42  func (cc *ConsensusChecks) GetByUpdatedKey(key string) []*ConsensusCheck {
    43  	var result []*ConsensusCheck
    44  	if _, ok := cc.affectedKeysByStateKey[key]; !ok {
    45  		return result
    46  	}
    47  
    48  	for id := range cc.affectedKeysByStateKey[key] {
    49  		if ConsensusCheck, ok := cc.checks[id]; ok {
    50  			result = append(result, ConsensusCheck)
    51  		}
    52  	}
    53  
    54  	return result
    55  }
    56  
    57  // iterate over all the keys stored in the set (map[string]empty) found in
    58  // the given key maps and populates a slice of pointers to ConsensusCheck values
    59  // that is returned as a set of ConsensusCheck updated by the given keys
    60  // with removed duplicates on it (as it is a "set").
    61  func (cc *ConsensusChecks) GetByUpdatedKeys(keys []string) []*ConsensusCheck {
    62  	var result []*ConsensusCheck
    63  
    64  	temporaryIDs := make(map[string]empty)
    65  
    66  	for _, key := range keys {
    67  		if _, ok := cc.affectedKeysByStateKey[key]; !ok {
    68  			continue
    69  		}
    70  
    71  		for id := range cc.affectedKeysByStateKey[key] {
    72  			if ConsensusCheck, ok := cc.checks[id]; ok {
    73  				if _, ok := temporaryIDs[id]; !ok {
    74  					temporaryIDs[id] = empty{}
    75  
    76  					result = append(result, ConsensusCheck)
    77  				}
    78  			}
    79  		}
    80  	}
    81  
    82  	return result
    83  }
    84  
    85  // adds a new pointer to a ConsensusCheck value in the storage
    86  // and registers its affected by keys index.
    87  func (cc *ConsensusChecks) Add(id string, check *ConsensusCheck) {
    88  	cc.checks[id] = check
    89  	cc.registerAffectedKeys(id, check.affectedKeys)
    90  }
    91  
    92  // Remove removes the given ConsensusCheck identity from the storage and
    93  // removes its affected by keys index if needed after cleaning.
    94  func (cc *ConsensusChecks) Remove(id string) {
    95  	if _, ok := cc.affectedKeysByStateKey[id]; ok {
    96  		delete(cc.affectedKeysByStateKey, id)
    97  		cc.unregisterAffectedKeys(id)
    98  	}
    99  }
   100  
   101  func (cc *ConsensusChecks) registerAffectedKeys(id string, keys []string) {
   102  	for _, key := range keys {
   103  		if _, ok := cc.affectedKeysByStateKey[key]; ok {
   104  			cc.affectedKeysByStateKey[key][id] = empty{}
   105  		} else {
   106  			cc.affectedKeysByStateKey[key] = map[string]empty{id: {}}
   107  		}
   108  	}
   109  }
   110  
   111  func (cc *ConsensusChecks) unregisterAffectedKeys(id string) {
   112  	var keysToDelete []string
   113  
   114  	for key, internal := range cc.affectedKeysByStateKey {
   115  		if _, ok := internal[id]; ok {
   116  			delete(cc.affectedKeysByStateKey[key], id)
   117  
   118  			if len(cc.affectedKeysByStateKey[key]) == 0 {
   119  				keysToDelete = append(keysToDelete, key)
   120  			}
   121  		}
   122  	}
   123  
   124  	for _, key := range keysToDelete {
   125  		delete(cc.affectedKeysByStateKey, key)
   126  	}
   127  }