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 }