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  }