github.com/polarismesh/polaris@v1.17.8/plugin/healthchecker/leader/beat_cache.go (about) 1 /** 2 * Tencent is pleased to support the open source community by making Polaris available. 3 * 4 * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 5 * 6 * Licensed under the BSD 3-Clause License (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * https://opensource.org/licenses/BSD-3-Clause 11 * 12 * Unless required by applicable law or agreed to in writing, software distributed 13 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 14 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 15 * specific language governing permissions and limitations under the License. 16 */ 17 18 package leader 19 20 import ( 21 "strconv" 22 "sync" 23 24 apiservice "github.com/polarismesh/specification/source/go/api/v1/service_manage" 25 "go.uber.org/zap" 26 27 "github.com/polarismesh/polaris/common/utils" 28 ) 29 30 // ReadBeatRecord Heartbeat records read results 31 type ReadBeatRecord struct { 32 Record RecordValue 33 Exist bool 34 } 35 36 // WriteBeatRecord Heartbeat record operation results 37 type WriteBeatRecord struct { 38 Record RecordValue 39 Key string 40 } 41 42 // RecordValue heatrtbeat record value 43 type RecordValue struct { 44 Server string 45 CurTimeSec int64 46 Count int64 47 } 48 49 func (r RecordValue) String() string { 50 secStr := strconv.FormatInt(r.CurTimeSec, 10) 51 countStr := strconv.FormatInt(r.Count, 10) 52 return r.Server + Split + secStr + Split + countStr 53 } 54 55 type ( 56 // HashFunction hash function to caul record id need locate in SegmentMap 57 HashFunction func(string) int 58 // RecordSaver beat record saver 59 RecordSaver func(req *apiservice.HeartbeatsRequest) 60 // RecordDelter beat record delter 61 RecordDelter func(req *apiservice.DelHeartbeatsRequest) 62 // RecordGetter beat record getter 63 RecordGetter func(req *apiservice.GetHeartbeatsRequest) *apiservice.GetHeartbeatsResponse 64 // BeatRecordCache Heartbeat data cache 65 BeatRecordCache interface { 66 // Get get records 67 Get(keys ...string) map[string]*ReadBeatRecord 68 // Put put records 69 Put(records ...WriteBeatRecord) 70 // Del del records 71 Del(keys ...string) 72 // Clean . 73 Clean() 74 // Snapshot 75 Snapshot() map[string]*ReadBeatRecord 76 } 77 ) 78 79 // newLocalBeatRecordCache 80 func newLocalBeatRecordCache(soltNum int32, hashFunc HashFunction) BeatRecordCache { 81 if soltNum == 0 { 82 soltNum = DefaultSoltNum 83 } 84 return &LocalBeatRecordCache{ 85 soltNum: soltNum, 86 hashFunc: hashFunc, 87 beatCache: utils.NewSegmentMap[string, RecordValue](int(soltNum), func(k string) int { 88 return hashFunc(k) 89 }), 90 } 91 } 92 93 // LocalBeatRecordCache 94 type LocalBeatRecordCache struct { 95 lock sync.RWMutex 96 soltNum int32 97 hashFunc HashFunction 98 beatCache *utils.SegmentMap[string, RecordValue] 99 } 100 101 func (lc *LocalBeatRecordCache) Get(keys ...string) map[string]*ReadBeatRecord { 102 lc.lock.RLock() 103 defer lc.lock.RUnlock() 104 ret := make(map[string]*ReadBeatRecord, len(keys)) 105 for i := range keys { 106 key := keys[i] 107 val, ok := lc.beatCache.Get(key) 108 ret[key] = &ReadBeatRecord{ 109 Record: val, 110 Exist: ok, 111 } 112 } 113 return ret 114 } 115 116 func (lc *LocalBeatRecordCache) Put(records ...WriteBeatRecord) { 117 lc.lock.RLock() 118 defer lc.lock.RUnlock() 119 for i := range records { 120 record := records[i] 121 if log.DebugEnabled() { 122 plog.Debug("receive put action", zap.Any("record", record)) 123 } 124 lc.beatCache.Put(record.Key, record.Record) 125 } 126 } 127 128 func (lc *LocalBeatRecordCache) Del(keys ...string) { 129 lc.lock.RLock() 130 defer lc.lock.RUnlock() 131 for i := range keys { 132 key := keys[i] 133 ok := lc.beatCache.Del(key) 134 if log.DebugEnabled() { 135 plog.Debug("delete result", zap.String("key", key), zap.Bool("exist", ok)) 136 } 137 } 138 } 139 140 func (lc *LocalBeatRecordCache) Clean() { 141 lc.lock.Lock() 142 defer lc.lock.Unlock() 143 lc.beatCache = utils.NewSegmentMap[string, RecordValue](int(lc.soltNum), func(k string) int { 144 return lc.hashFunc(k) 145 }) 146 } 147 148 func (lc *LocalBeatRecordCache) Snapshot() map[string]*ReadBeatRecord { 149 lc.lock.RLock() 150 defer lc.lock.RUnlock() 151 ret := map[string]*ReadBeatRecord{} 152 lc.beatCache.Range(func(k string, v RecordValue) { 153 ret[k] = &ReadBeatRecord{ 154 Record: v, 155 } 156 }) 157 return ret 158 } 159 160 // newRemoteBeatRecordCache 161 func newRemoteBeatRecordCache(getter RecordGetter, saver RecordSaver, 162 delter RecordDelter) BeatRecordCache { 163 return &RemoteBeatRecordCache{ 164 getter: getter, 165 saver: saver, 166 delter: delter, 167 } 168 } 169 170 // RemoteBeatRecordCache 171 type RemoteBeatRecordCache struct { 172 saver RecordSaver 173 delter RecordDelter 174 getter RecordGetter 175 } 176 177 func (rc *RemoteBeatRecordCache) Get(keys ...string) map[string]*ReadBeatRecord { 178 ret := make(map[string]*ReadBeatRecord) 179 for i := range keys { 180 ret[keys[i]] = &ReadBeatRecord{ 181 Exist: false, 182 } 183 } 184 resp := rc.getter(&apiservice.GetHeartbeatsRequest{ 185 InstanceIds: keys, 186 }) 187 records := resp.GetRecords() 188 for i := range records { 189 record := records[i] 190 val, ok := ret[record.InstanceId] 191 if !ok { 192 val.Exist = false 193 continue 194 } 195 val.Exist = record.GetExist() 196 val.Record = RecordValue{ 197 CurTimeSec: record.GetLastHeartbeatSec(), 198 } 199 } 200 return ret 201 } 202 203 func (rc *RemoteBeatRecordCache) Put(records ...WriteBeatRecord) { 204 req := &apiservice.HeartbeatsRequest{ 205 Heartbeats: make([]*apiservice.InstanceHeartbeat, 0, len(records)), 206 } 207 for i := range records { 208 record := records[i] 209 req.Heartbeats = append(req.Heartbeats, &apiservice.InstanceHeartbeat{ 210 InstanceId: record.Key, 211 }) 212 } 213 rc.saver(req) 214 } 215 216 func (rc *RemoteBeatRecordCache) Del(key ...string) { 217 req := &apiservice.DelHeartbeatsRequest{ 218 InstanceIds: key, 219 } 220 rc.delter(req) 221 } 222 223 func (lc *RemoteBeatRecordCache) Clean() { 224 // do nothing 225 } 226 227 func (lc *RemoteBeatRecordCache) Snapshot() map[string]*ReadBeatRecord { 228 return map[string]*ReadBeatRecord{} 229 }