github.com/matrixorigin/matrixone@v1.2.0/pkg/gossip/delegate.go (about) 1 // Copyright 2021 - 2023 Matrix Origin 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package gossip 16 17 import ( 18 "encoding/binary" 19 "fmt" 20 21 "github.com/hashicorp/memberlist" 22 "github.com/matrixorigin/matrixone/pkg/pb/gossip" 23 "github.com/matrixorigin/matrixone/pkg/pb/query" 24 "github.com/matrixorigin/matrixone/pkg/pb/statsinfo" 25 "github.com/matrixorigin/matrixone/pkg/queryservice/client" 26 "github.com/pierrec/lz4/v4" 27 "go.uber.org/zap" 28 ) 29 30 var ( 31 binaryEnc = binary.BigEndian 32 ) 33 34 type Module interface { 35 // Data returns all data that need to send to other nodes. 36 // The second return value is the left size of the limit size. 37 Data(limit int) ([]gossip.GossipData, int) 38 } 39 40 type delegate struct { 41 logger *zap.Logger 42 //cacheServiceAddr is the service address of the remote cache server. 43 cacheServiceAddr string 44 45 // dataCacheKey keeps the key cache of local set/delete 46 // items and remote key info. 47 // dataCacheKey *DataCacheKey 48 dataCacheKey *BaseStore[query.CacheKey] 49 50 // statsInfoKey keeps the keys of stats info. 51 statsInfoKey *BaseStore[statsinfo.StatsInfoKey] 52 } 53 54 func newDelegate(logger *zap.Logger, addr string) *delegate { 55 d := &delegate{ 56 logger: logger, 57 cacheServiceAddr: addr, 58 dataCacheKey: newBaseStore[query.CacheKey](addr), 59 statsInfoKey: newBaseStore[statsinfo.StatsInfoKey](addr), 60 } 61 return d 62 } 63 64 func (d *delegate) getDataCacheKey() client.KeyRouter[query.CacheKey] { 65 return d.dataCacheKey 66 } 67 68 func (d *delegate) getStatsInfoKey() client.KeyRouter[statsinfo.StatsInfoKey] { 69 return d.statsInfoKey 70 } 71 72 // NodeMeta implements the memberlist.Delegate interface. 73 func (d *delegate) NodeMeta(limit int) []byte { 74 meta := []byte(d.cacheServiceAddr) 75 if len(meta) > limit { 76 panic(fmt.Sprintf("meta size %d is larger then limit %d", len(meta), limit)) 77 } 78 return meta 79 } 80 81 // NotifyMsg implements the memberlist.Delegate interface. 82 func (d *delegate) NotifyMsg(data []byte) { 83 if len(data) == 0 { 84 return 85 } 86 var item gossip.GossipData 87 if err := item.Unmarshal(data); err != nil { 88 d.logger.Error("failed to unmarshal cache item from buf", zap.Error(err)) 89 return 90 } 91 switch t := item.Data.(type) { 92 case *gossip.GossipData_CacheKeyItem: 93 d.dataCacheKey.mu.Lock() 94 defer d.dataCacheKey.mu.Unlock() 95 m := d.dataCacheKey.mu.keyTarget 96 97 if t.CacheKeyItem.Operation == gossip.Operation_Set { 98 m[t.CacheKeyItem.CacheKey] = t.CacheKeyItem.TargetAddress 99 } else if t.CacheKeyItem.Operation == gossip.Operation_Delete { 100 delete(m, t.CacheKeyItem.CacheKey) 101 } 102 103 case *gossip.GossipData_StatsInfoKeyItem: 104 d.statsInfoKey.mu.Lock() 105 defer d.statsInfoKey.mu.Unlock() 106 m := d.statsInfoKey.mu.keyTarget 107 108 if t.StatsInfoKeyItem.Operation == gossip.Operation_Set { 109 m[t.StatsInfoKeyItem.StatsInfoKey] = t.StatsInfoKeyItem.TargetAddress 110 } else if t.StatsInfoKeyItem.Operation == gossip.Operation_Delete { 111 delete(m, t.StatsInfoKeyItem.StatsInfoKey) 112 } 113 } 114 } 115 116 func (d *delegate) broadcastData(limit int) []gossip.GossipData { 117 left := limit 118 items, left := d.dataCacheKey.Data(left) 119 data := make([]gossip.GossipData, len(items)) 120 for _, item := range items { 121 data = append(data, gossip.GossipData{ 122 Data: &gossip.GossipData_CacheKeyItem{ 123 CacheKeyItem: &gossip.CacheKeyItem{ 124 Operation: item.Operation, 125 TargetAddress: item.TargetAddress, 126 CacheKey: *item.Key.(*gossip.CommonItem_CacheKey).CacheKey, 127 }, 128 }, 129 }) 130 } 131 if left == 0 { 132 return data 133 } 134 135 items, _ = d.statsInfoKey.Data(left) 136 for _, item := range items { 137 data = append(data, gossip.GossipData{ 138 Data: &gossip.GossipData_StatsInfoKeyItem{ 139 StatsInfoKeyItem: &gossip.StatsInfoKeyItem{ 140 Operation: item.Operation, 141 TargetAddress: item.TargetAddress, 142 StatsInfoKey: *item.Key.(*gossip.CommonItem_StatsInfoKey).StatsInfoKey, 143 }, 144 }, 145 }) 146 } 147 148 return data 149 } 150 151 // GetBroadcasts implements the memberlist.Delegate interface. 152 func (d *delegate) GetBroadcasts(overhead, limit int) [][]byte { 153 // For the case that node leave from cluster. 154 if d == nil { 155 return nil 156 } 157 items := d.broadcastData(limit - overhead) 158 data := make([][]byte, 0, len(items)) 159 for _, item := range items { 160 bytes, err := item.Marshal() 161 if err != nil { 162 d.logger.Error("failed to marshal item", zap.Error(err)) 163 return nil 164 } 165 data = append(data, bytes) 166 } 167 return data 168 } 169 170 func (d *delegate) dataCacheState() map[string]*query.CacheKeys { 171 d.dataCacheKey.mu.Lock() 172 defer d.dataCacheKey.mu.Unlock() 173 targetCacheKeys := make(map[string]*query.CacheKeys) 174 for key, target := range d.dataCacheKey.mu.keyTarget { 175 if _, ok := targetCacheKeys[target]; !ok { 176 targetCacheKeys[target] = &query.CacheKeys{} 177 } 178 targetCacheKeys[target].Keys = append(targetCacheKeys[target].Keys, key) 179 } 180 return targetCacheKeys 181 } 182 183 func (d *delegate) statsInfoState() map[string]*statsinfo.StatsInfoKeys { 184 d.dataCacheKey.mu.Lock() 185 defer d.dataCacheKey.mu.Unlock() 186 targetStatsInfo := make(map[string]*statsinfo.StatsInfoKeys) 187 for key, target := range d.statsInfoKey.mu.keyTarget { 188 if _, ok := targetStatsInfo[target]; !ok { 189 targetStatsInfo[target] = &statsinfo.StatsInfoKeys{} 190 } 191 targetStatsInfo[target].Keys = append(targetStatsInfo[target].Keys, key) 192 } 193 return targetStatsInfo 194 } 195 196 // LocalState implements the memberlist.Delegate interface. 197 func (d *delegate) LocalState(join bool) []byte { 198 // If this a join action, there is no user data on this node. 199 if join { 200 return nil 201 } 202 targetState := gossip.TargetState{ 203 Data: map[string]*gossip.LocalState{}, 204 } 205 206 for addr, st := range d.dataCacheState() { 207 _, ok := targetState.Data[addr] 208 if !ok { 209 targetState.Data[addr] = &gossip.LocalState{} 210 } 211 targetState.Data[addr].CacheKeys = *st 212 } 213 214 for addr, st := range d.statsInfoState() { 215 _, ok := targetState.Data[addr] 216 if !ok { 217 targetState.Data[addr] = &gossip.LocalState{} 218 } 219 targetState.Data[addr].StatsInfoKeys = *st 220 } 221 222 data, err := targetState.Marshal() 223 if err != nil { 224 d.logger.Error("failed to marshal cache data", zap.Error(err)) 225 return nil 226 } 227 dst := make([]byte, lz4.CompressBlockBound(len(data)+4)) 228 l := lz4.Compressor{} 229 n, err := l.CompressBlock(data, dst[4:]) 230 if err != nil { 231 d.logger.Error("failed to compress cache data", zap.Error(err)) 232 return nil 233 } 234 binaryEnc.PutUint32(dst, uint32(len(data))) 235 return dst[:n+4] 236 } 237 238 // MergeRemoteState implements the memberlist.Delegate interface. 239 func (d *delegate) MergeRemoteState(buf []byte, join bool) { 240 // We do NOT merge remote user data if this is a pull/push action. 241 // Means that, we only accept user data from a remote node when this 242 // is a new node and is trying to join to the gossip cluster. 243 if !join { 244 return 245 } 246 sz := binaryEnc.Uint32(buf) 247 dst := make([]byte, sz) 248 n, err := lz4.UncompressBlock(buf[4:], dst) 249 if err != nil { 250 d.logger.Error("failed to uncompress cache data from buf", zap.Error(err)) 251 return 252 } 253 dst = dst[:n] 254 targetState := gossip.TargetState{} 255 if err := targetState.Unmarshal(dst); err != nil { 256 d.logger.Error("failed to unmarshal cache data", zap.Error(err)) 257 return 258 } 259 260 for target, state := range targetState.Data { 261 d.dataCacheKey.update(target, state.CacheKeys.Keys) 262 d.statsInfoKey.update(target, state.StatsInfoKeys.Keys) 263 } 264 } 265 266 // NotifyJoin implements the memberlist.EventDelegate interface. 267 func (d *delegate) NotifyJoin(*memberlist.Node) {} 268 269 // NotifyLeave implements the memberlist.EventDelegate interface. 270 func (d *delegate) NotifyLeave(node *memberlist.Node) { 271 cacheServiceAddr := string(node.Meta) 272 if len(cacheServiceAddr) == 0 { 273 return 274 } 275 d.dataCacheKey.mu.Lock() 276 defer d.dataCacheKey.mu.Unlock() 277 for key, target := range d.dataCacheKey.mu.keyTarget { 278 if cacheServiceAddr == target { 279 delete(d.dataCacheKey.mu.keyTarget, key) 280 } 281 } 282 } 283 284 // NotifyUpdate implements the memberlist.EventDelegate interface. 285 func (d *delegate) NotifyUpdate(*memberlist.Node) {}